Skip to content
Merged
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
23 changes: 23 additions & 0 deletions docs/tileop-usage/b-subview-b-assemble.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,29 @@ unboxed `CUBE_M32` Local Tile;dtype、location、physical/valid shape 和
fragment capacity 必须一致。`TADD`、`TSUB`、`TMUL`、`TDIV`、`TREM`、
`TAND`、`TOR`、`TXOR`、`TSHL`、`TSHR`、`TMAX`、`TMIN` 共用此路径。

二元 producer 也可以混用一个 `TPARTVIEW` fragment 和一个普通
`CUBE_M32` Tile,两个源顺序都受支持。view 所在的 source binder 携带一个
`B.SUBVIEW 0/1`,destination binder 同时携带 `B.ASSEMBLE`,不需要先用
`TADDS(x, 0)`、`TCVT` 或 `TMOV` 把 view 物化:

```cpp
Parent assemble_mixed(Parent &parent, Fragment &tile) {
auto view = TPARTVIEW<Fragment, 1, 8>(parent)[0][7];
TileArray<Fragment, 1, 8> slots;
for (int col = 0; col < 8; ++col) {
if ((col & 1) == 0)
TADD(slots[0][col], view, tile); // source 0 携带 B.SUBVIEW
else
TADD(slots[0][col], tile, view); // source 1 携带 B.SUBVIEW
}
return TASSEMBLY<Parent>(std::move(slots));
}
```

mixed 路径同样要求 slot、view fragment 和普通 Tile 的 CUBE_M32 layout、
dtype、location、physical/valid shape 与 fragment capacity 全部一致,并适用于
上述完整二元操作族。

source 侧对应物是 `TPARTVIEW`:`B.ASSEMBLE` 把 producer 的 destination 写进
parent 的某个 slot,`B.SUBVIEW` 则把 parent 的某段借出为 source fragment,
两者互为读写对偶。
Expand Down
193 changes: 193 additions & 0 deletions include/common/pto_tile_region_inline_asm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2119,6 +2119,181 @@ PTO_REGION_ALWAYS_INLINE void pto_region_binary_tile_assemble_dispatch(
}
}

// A mixed binary assembly producer binds one parent-backed CUBE_M32 fragment
// through B.SUBVIEW and one ordinary CUBE_M32 Tile directly. The bool records
// the mathematical source position of the view so B.SUBVIEW selects the same
// source independently of the C++ parameter order used internally here.
template <int ParentSize, bool Init, bool Last, int Opcode, bool ViewIsSrc0,
typename SubTile, typename SourceParent, typename SourceSubTile,
typename Tile>
requires(is_tile_data_v<Tile> && !is_subtile_view_v<Tile> &&
!is_range_v<Tile>)
PTO_REGION_ALWAYS_INLINE void pto_region_binary_mixed_assemble(
region::TileArrayOutputRef<SubTile> &dst,
region::SubTileView<SourceParent, SourceSubTile> &view, Tile &tile) {
static_assert(SubTile::BFractal == BLayout::CubeM32 &&
SourceSubTile::BFractal == BLayout::CubeM32 &&
Tile::BFractal == BLayout::CubeM32,
"binary TileArray mixed-source assembly requires CUBE_M32 "
"destination and sources");
static_assert(SubTile::SFractal == SLayout::NoneBox &&
SourceSubTile::SFractal == SLayout::NoneBox &&
Tile::SFractal == SLayout::NoneBox,
"binary TileArray mixed-source assembly requires unboxed "
"fragments");
static_assert(SubTile::Loc == SourceSubTile::Loc &&
SourceSubTile::Loc == Tile::Loc,
"binary TileArray slot and mixed sources must have matching "
"locations");
static_assert(SubTile::Rows == SourceSubTile::Rows &&
SubTile::Cols == SourceSubTile::Cols &&
SourceSubTile::Rows == Tile::Rows &&
SourceSubTile::Cols == Tile::Cols,
"binary TileArray slot requires matching physical shapes");
static_assert(SubTile::ValidRow == SourceSubTile::ValidRow &&
SubTile::ValidCol == SourceSubTile::ValidCol &&
SourceSubTile::ValidRow == Tile::ValidRow &&
SourceSubTile::ValidCol == Tile::ValidCol,
"binary TileArray slot requires matching valid shapes");
static_assert(
std::is_same_v<typename SubTile::DType,
typename SourceSubTile::DType> &&
std::is_same_v<typename SourceSubTile::DType, typename Tile::DType>,
"binary TileArray slot requires matching element types");
static_assert(SubTile::LogicalTileBytes ==
SourceSubTile::LogicalTileBytes &&
SourceSubTile::LogicalTileBytes == Tile::LogicalTileBytes,
"binary TileArray slot and mixed sources must have matching "
"capacities");

constexpr int writer_size =
tile_type_traits<typename SubTile::TileDType>::TilesizeCode;
constexpr int subview_size =
tile_type_traits<typename SourceSubTile::TileDType>::TilesizeCode;
static_assert(writer_size != 0,
"TileArray slot writer extent must be a nonzero size code");
static_assert(subview_size != 0,
"mixed-source B.SUBVIEW extent must be a nonzero size code");
const uintptr_t source_base_units = view.GetRangeBase();
const uintptr_t destination_base_units = dst.range_base_units();

#define PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX \
"BSTART.TEPL %c[Opcode], %D[Type]\n" PTO_REGION_ELEMENTWISE_LAYOUT_ASM \
"B.DIM zero, %c[ValidCol], ->lb0\n" \
"B.DIM zero, %c[ValidRow], ->lb1\n" \
"B.DIM zero, %c[Cols], ->lb2\n"
#define PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS \
[Type] "i"(type_traits<typename SourceSubTile::DType>::TypeCode), \
[View] "Tr"(view.data()), [Tile] "Tr"(tile.data()), \
[ValidCol] "i"(SourceSubTile::ValidCol), \
[ValidRow] "i"(SourceSubTile::ValidRow), \
[Cols] "i"(SourceSubTile::Cols), [ParentSize] "i"(ParentSize), \
[SourceOffset] "r"(source_base_units), \
[DestinationOffset] "r"(destination_base_units), [Opcode] "i"(Opcode), \
[SubviewSize] "i"(subview_size), [WriterSize] "i"(writer_size), \
[Init] "i"(Init), [Last] "i"(Last), \
[ElemLayout] "i"(local_layout_code_v<SubTile>)
if constexpr (Init && ViewIsSrc0) {
asm volatile(
PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX
"B.IOT %[View], %[Tile], mask=1111, last, "
"->%[Dst]<%Z[ParentSize]>\n"
"B.SUBVIEW 0, %[SourceOffset], 0, %c[SubviewSize]\n"
"B.ASSEMBLE %c[Init], %c[Last], %[DestinationOffset], 0, "
"%c[WriterSize]\n"
: [Dst] "=Tr"(dst.template parent_data<ParentSize>())
: PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS
: "memory");
} else if constexpr (Init) {
asm volatile(
PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX
"B.IOT %[Tile], %[View], mask=1111, last, "
"->%[Dst]<%Z[ParentSize]>\n"
"B.SUBVIEW 1, %[SourceOffset], 0, %c[SubviewSize]\n"
"B.ASSEMBLE %c[Init], %c[Last], %[DestinationOffset], 0, "
"%c[WriterSize]\n"
: [Dst] "=Tr"(dst.template parent_data<ParentSize>())
: PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS
: "memory");
} else if constexpr (ViewIsSrc0) {
asm volatile(PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX
"B.IOT %[View], %[Tile], mask=1111\n"
"B.SUBVIEW 0, %[SourceOffset], 0, %c[SubviewSize]\n"
"B.IOT %[Dst], mask=1111, last\n"
"B.ASSEMBLE %c[Init], %c[Last], "
"%[DestinationOffset], 0, %c[WriterSize]\n"
:
: [Dst] "Tr"(dst.template parent_data<ParentSize>()),
PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS
: "memory");
} else {
asm volatile(PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX
"B.IOT %[Tile], %[View], mask=1111\n"
"B.SUBVIEW 1, %[SourceOffset], 0, %c[SubviewSize]\n"
"B.IOT %[Dst], mask=1111, last\n"
"B.ASSEMBLE %c[Init], %c[Last], "
"%[DestinationOffset], 0, %c[WriterSize]\n"
:
: [Dst] "Tr"(dst.template parent_data<ParentSize>()),
PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS
: "memory");
}
#undef PTO_REGION_BINARY_MIXED_ASSEMBLY_INPUTS
#undef PTO_REGION_BINARY_MIXED_ASSEMBLY_PREFIX
}

template <int ParentSize, int Opcode, bool ViewIsSrc0, typename SubTile,
typename SourceParent, typename SourceSubTile, typename Tile>
requires(is_tile_data_v<Tile> && !is_subtile_view_v<Tile> &&
!is_range_v<Tile>)
PTO_REGION_ALWAYS_INLINE void pto_region_binary_mixed_assemble_phase(
region::TileArrayOutputRef<SubTile> &dst,
region::SubTileView<SourceParent, SourceSubTile> &view, Tile &tile) {
if (dst.slot_count() == 1)
pto_region_binary_mixed_assemble<ParentSize, true, true, Opcode,
ViewIsSrc0>(dst, view, tile);
else if (dst.ordinal() == 0)
pto_region_binary_mixed_assemble<ParentSize, true, false, Opcode,
ViewIsSrc0>(dst, view, tile);
else if (dst.ordinal() == dst.slot_count() - 1)
pto_region_binary_mixed_assemble<ParentSize, false, true, Opcode,
ViewIsSrc0>(dst, view, tile);
else
pto_region_binary_mixed_assemble<ParentSize, false, false, Opcode,
ViewIsSrc0>(dst, view, tile);
}

template <int Opcode, bool ViewIsSrc0, typename SubTile, typename SourceParent,
typename SourceSubTile, typename Tile>
requires(is_tile_data_v<Tile> && !is_subtile_view_v<Tile> &&
!is_range_v<Tile>)
PTO_REGION_ALWAYS_INLINE void pto_region_binary_mixed_assemble_dispatch(
region::TileArrayOutputRef<SubTile> &dst,
region::SubTileView<SourceParent, SourceSubTile> &view, Tile &tile) {
switch (dst.parent_size_code()) {
#define PTO_REGION_BINARY_MIXED_PARENT_CASE(N) \
case N: \
pto_region_binary_mixed_assemble_phase<N, Opcode, ViewIsSrc0>(dst, view, \
tile); \
break
PTO_REGION_BINARY_MIXED_PARENT_CASE(1);
PTO_REGION_BINARY_MIXED_PARENT_CASE(2);
PTO_REGION_BINARY_MIXED_PARENT_CASE(3);
PTO_REGION_BINARY_MIXED_PARENT_CASE(4);
PTO_REGION_BINARY_MIXED_PARENT_CASE(5);
PTO_REGION_BINARY_MIXED_PARENT_CASE(6);
PTO_REGION_BINARY_MIXED_PARENT_CASE(7);
PTO_REGION_BINARY_MIXED_PARENT_CASE(8);
PTO_REGION_BINARY_MIXED_PARENT_CASE(9);
PTO_REGION_BINARY_MIXED_PARENT_CASE(10);
PTO_REGION_BINARY_MIXED_PARENT_CASE(11);
PTO_REGION_BINARY_MIXED_PARENT_CASE(12);
#undef PTO_REGION_BINARY_MIXED_PARENT_CASE
default:
__builtin_trap();
}
}

#define PTO_REGION_BINARY_DEST_WRAPPER(Name, Opcode) \
template <typename SubTile, typename Parent0, typename SubTile0, \
typename Parent1, typename SubTile1> \
Expand All @@ -2135,6 +2310,24 @@ PTO_REGION_ALWAYS_INLINE void pto_region_binary_tile_assemble_dispatch(
PTO_REGION_ALWAYS_INLINE void Name(region::TileArrayOutputRef<SubTile> dst, \
Src0 &src0, Src1 &src1) { \
pto_region_binary_tile_assemble_dispatch<Opcode>(dst, src0, src1); \
} \
template <typename SubTile, typename SourceParent, typename SourceSubTile, \
typename Tile> \
requires(is_tile_data_v<Tile> && !is_subtile_view_v<Tile> && \
!is_range_v<Tile>) \
PTO_REGION_ALWAYS_INLINE void Name( \
region::TileArrayOutputRef<SubTile> dst, \
region::SubTileView<SourceParent, SourceSubTile> &src0, Tile &src1) { \
pto_region_binary_mixed_assemble_dispatch<Opcode, true>(dst, src0, src1); \
} \
template <typename SubTile, typename Tile, typename SourceParent, \
typename SourceSubTile> \
requires(is_tile_data_v<Tile> && !is_subtile_view_v<Tile> && \
!is_range_v<Tile>) \
PTO_REGION_ALWAYS_INLINE void Name( \
region::TileArrayOutputRef<SubTile> dst, Tile &src0, \
region::SubTileView<SourceParent, SourceSubTile> &src1) { \
pto_region_binary_mixed_assemble_dispatch<Opcode, false>(dst, src1, src0); \
}

PTO_REGION_BINARY_DEST_WRAPPER(TADD, 0)
Expand Down
2 changes: 1 addition & 1 deletion test/tileop_api/compile.all
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ACTIVE_FIXTURES=(
TMatmulAccFullOptions TMatmulAccCScale TMatmulAllOptions TGEMVAllOptions TGEMVOperandOrder
PostProcessCombos SharedMatrixForms TCmpMode TColSumContract TSort TPrefetch MGatherCas MGatherAtomics MScatterAtomics
TMrgSort TQuant TImg2Col GroupMatmul TStoreShared TStoreAtomic SharedTLoad TAbs
DirectCubeLayout TileRegionBinaryMixed Issue166RmsNormB128 Issue269ReductionCapacity Issue272PackPrefix Issue274PackViews Issue275PackAssemble Issue276ReinterpretMul Issue288CubeM32BinaryAssembly TCvtSameTypeRounding
DirectCubeLayout TileRegionBinaryMixed Issue166RmsNormB128 Issue269ReductionCapacity Issue272PackPrefix Issue274PackViews Issue275PackAssemble Issue276ReinterpretMul Issue288CubeM32BinaryAssembly Issue299MixedBinaryAssembly TCvtSameTypeRounding
TAdd_mask TAdd TAdds TAnd TeplAss TeplAssSpecial TOrAssSubview TLoad TStore TCvt TDiv TDivs TExp TExpdif TMax TMaxs
RangeSubview RangeAssemble SharedRange TileRegionSharedSubview TileArray TileArrayCube TileArrayAssemblyOffsets TileArrayRegionAsm TileArrayTCVTE8M0 TileArrayWriterSize TileRegionUnaryAssembly TileRegion TileRegionUnary TileRegionBinary TileRegionBinaryAssembly TileRegionUnarySubviewAssembly TileRegionScalarAssembly TileRegionTCVTSubviewAssembly TileRegionTCVTSubview TileRegionShift TileRegionCubeSubview SubviewVecCube Issue138Subview Issue160ReductionPrefix Issue241ReductionPrefixBinary Issue187DynamicPrefix Issue178CubeTcvtNorm Issue195ConvCompose Issue194Timg2colNchw SubviewVecCubeIssue144
ValidShapeImmediate ValidShapePerDim ValidShapePerDimSweep CoopGroupMOverloads CubeInternalAcc TSELCanonical Issue200TcmpsGpr Issue203CubeTcvtTileArray IssueA2CubeMxFp4Tcvt Issue111SharedSlot Issue290PartialCompareSelect
Expand Down
13 changes: 13 additions & 0 deletions test/tileop_api/run_negatives.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ TCI2D_CASES="layout location dtype shape steps m16_rows"
I64_CASES="fp64_element unsupported_parent m16 short_m32 subview_pair assemble_pair writer_limit"
TCOLSUM_CASES="dest_rows dest_cols dtype"
ISSUE288_CASES="layout dtype shape valid_shape"
ISSUE299_CASES="layout dtype shape valid_shape location capacity"
ISSUE398399_CASES="atomic_add_dtype atomic_inc_dtype atomic_cube_n8 atomic_mask_rowmajor atomic_mask_shape atomic_mask_shared atomic_pe_mask cube_shared_dtype cube_shared_cols cube_shared_capacity cube_shared_writer_size"
PASS=0; FAIL=0

Expand Down Expand Up @@ -120,6 +121,18 @@ for c in $ISSUE288_CASES; do
esac
expect_rejected "issue288_$c" "$define" Issue288Negatives.cpp "$pattern"
done
for c in $ISSUE299_CASES; do
define=SHOULD_FAIL_ISSUE299_$(echo "$c" | tr '[:lower:]' '[:upper:]')
case "$c" in
layout) pattern='mixed-source assembly requires CUBE_M32' ;;
dtype) pattern='requires matching element types' ;;
shape) pattern='requires matching physical shapes' ;;
valid_shape) pattern='requires matching valid shapes' ;;
location) pattern='mixed sources must have matching locations' ;;
capacity) pattern='mixed sources must have matching capacities' ;;
esac
expect_rejected "issue299_$c" "$define" Issue299Negatives.cpp "$pattern"
done
for c in $ISSUE398399_CASES; do
define=SHOULD_FAIL_$(echo "$c" | tr '[:lower:]' '[:upper:]')
pattern='atomic TSTORE|CUBE_N8|CUBE-to-Shared-ND|Shared ND|B\.ASSEMBLE|writer range'
Expand Down
82 changes: 82 additions & 0 deletions test/tileop_api/src/Issue299MixedBinaryAssembly.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <common/pto_tileop.hpp>

#include <cstdint>
#include <utility>

using namespace pto;

using Fragment = VecTileM32<int32_t, 32, 1>;
using Parent = VecTileM32<int32_t, 32, 8>;

static_assert(Fragment::LogicalTileBytes == 128);
static_assert(Parent::LogicalTileBytes == 1024);

__attribute__((noinline)) Parent assemble_view_tile(Parent &parent,
Fragment &rhs) {
auto lhs = TPARTVIEW<Fragment, 1, 8>(parent)[0][7];
TileArray<Fragment, 1, 8> slots;
TADD(slots[0][0], lhs, rhs);
TADD(slots[0][1], lhs, rhs);
TADD(slots[0][2], lhs, rhs);
TADD(slots[0][3], lhs, rhs);
TADD(slots[0][4], lhs, rhs);
TADD(slots[0][5], lhs, rhs);
TADD(slots[0][6], lhs, rhs);
TADD(slots[0][7], lhs, rhs);
return TASSEMBLY<Parent>(std::move(slots));
}

__attribute__((noinline)) Parent assemble_tile_view(Fragment &lhs,
Parent &parent) {
auto rhs = TPARTVIEW<Fragment, 1, 8>(parent)[0][6];
TileArray<Fragment, 1, 8> slots;
TADD(slots[0][0], lhs, rhs);
TADD(slots[0][1], lhs, rhs);
TADD(slots[0][2], lhs, rhs);
TADD(slots[0][3], lhs, rhs);
TADD(slots[0][4], lhs, rhs);
TADD(slots[0][5], lhs, rhs);
TADD(slots[0][6], lhs, rhs);
TADD(slots[0][7], lhs, rhs);
return TASSEMBLY<Parent>(std::move(slots));
}

#define INSTANTIATE_MIXED_BINARY(Name) \
do { \
TileArray<Fragment, 1, 1> left_slots; \
Name(left_slots[0][0], view, tile); \
Fragment left = TASSEMBLY<Fragment>(std::move(left_slots)); \
TileArray<Fragment, 1, 1> right_slots; \
Name(right_slots[0][0], tile, view); \
Fragment right = TASSEMBLY<Fragment>(std::move(right_slots)); \
asm volatile("" : : "Tr"(left.data()), "Tr"(right.data())); \
} while (false)

__attribute__((noinline)) void instantiate_all_mixed_binary(Parent &parent,
Fragment &tile) {
auto view = TPARTVIEW<Fragment, 1, 8>(parent)[0][0];
INSTANTIATE_MIXED_BINARY(TADD);
INSTANTIATE_MIXED_BINARY(TSUB);
INSTANTIATE_MIXED_BINARY(TMUL);
INSTANTIATE_MIXED_BINARY(TDIV);
INSTANTIATE_MIXED_BINARY(TREM);
INSTANTIATE_MIXED_BINARY(TAND);
INSTANTIATE_MIXED_BINARY(TOR);
INSTANTIATE_MIXED_BINARY(TXOR);
INSTANTIATE_MIXED_BINARY(TSHL);
INSTANTIATE_MIXED_BINARY(TSHR);
INSTANTIATE_MIXED_BINARY(TMAX);
INSTANTIATE_MIXED_BINARY(TMIN);
}

#undef INSTANTIATE_MIXED_BINARY

int main() {
Parent source_parent;
Fragment tile;
Parent left = assemble_view_tile(source_parent, tile);
Parent right = assemble_tile_view(tile, source_parent);
instantiate_all_mixed_binary(source_parent, tile);
asm volatile("" : : "Tr"(left.data()), "Tr"(right.data()));
return 0;
}
Loading
Loading