-
Notifications
You must be signed in to change notification settings - Fork 74
feat: 支持 tput/tget 动态分区 shape #1079
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10201,7 +10201,7 @@ This section documents PTO communication primitives. PTOAS currently exposes: | |
|
|
||
| ##### `pto.comm.tput` - Synchronous Remote Write | ||
|
|
||
| **Summary:** Lowers to `pto::comm::TPUT(...)` and copies data from local GM to remote GM through a VEC staging tile. | ||
| **Summary:** Copies data synchronously from local GM to remote GM through a VEC staging tile. | ||
|
|
||
| **Arguments:** | ||
|
|
||
|
|
@@ -10214,9 +10214,29 @@ This section documents PTO communication primitives. PTOAS currently exposes: | |
|
|
||
| **Constraints & Verification:** | ||
|
|
||
| - `dst` / `src` must be GM-shaped values with positive static shapes. | ||
| - `dst` and `src` must have the same element type and static shape. | ||
| - `ping` / `pong` must be local VEC tile-like values whose element type matches `src`. | ||
| - `dst` / `src` must be GM-shaped values. Static dimensions must be positive. | ||
| - Dynamic dimensions are supported only when both operands are | ||
| `pto.partition_tensor_view` values. | ||
| - `dst` and `src` must have the same element type and identical static/dynamic | ||
| shape signatures. Corresponding dynamic extents must be equal at runtime. | ||
| - Runtime extents must be nonnegative, and each partition range must remain | ||
| within its backing tensor view. A zero extent denotes an empty transfer. | ||
|
Comment on lines
+10222
to
+10223
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an empty transfer is statically known, the documented zero-length behavior cannot be expressed through the supported Useful? React with 👍 / 👎. |
||
| - `ping` / `pong` must be local VEC tile-like values whose element type matches | ||
| `src`. Their physical `rows` / `cols` must be positive static values. | ||
| - Staging `v_row` / `v_col` values must be positive and may be static or | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bullet documents only half of the runtime contract, and a program that follows it exactly can still produce the out-of-bounds write I describe in the note on The divisibility rule stated here applies to the chunked path. But if (totalLogicalRows <= ubChunkRows && logicalDims[4] <= ubChunkCols) {
TLOAD(stagingTileData, srcGlobalData); ...; TSTORE_IMPL(dstGlobalData, stagingTileData); return;
}The single-shot branch requires something stricter that is written down nowhere: So a transfer with a dynamic extent of 100 and |
||
| dynamic. If a transfer enters the chunked path, a static `v_row` / `v_col` | ||
| must exactly divide the corresponding logical row / column extent. Use | ||
| dynamic valid dimensions when a partial final chunk is possible. | ||
| - When `pong` is present, it must have the same type as `ping`. | ||
|
|
||
| **Semantics:** | ||
|
|
||
| For every logical index in the common `src` / `dst` shape, the operation reads | ||
| the local `src` element and writes the corresponding remote `dst` element. | ||
| `atomic_none` performs a normal write; an atomic mode such as `atomic_add` | ||
| combines the source value with the destination according to that mode. The | ||
| staging bundle may divide the logical range into chunks but does not change the | ||
| logical transfer extent. | ||
|
|
||
| **Examples:** | ||
|
|
||
|
|
@@ -10228,11 +10248,36 @@ pto.comm.tput(%dst, %src, buf(%ping) : !pto.partition_tensor_view<128xf32>, !pto | |
| pto.comm.tput(%dst, %src, buf(%ping, %pong) : !pto.partition_tensor_view<128xf32>, !pto.partition_tensor_view<128xf32>, !pto.tile_buf<loc=vec, dtype=f32, rows=1, cols=128, v_row=1, v_col=128, blayout=row_major, slayout=none_box, fractal=512, pad=0>, !pto.tile_buf<loc=vec, dtype=f32, rows=1, cols=128, v_row=1, v_col=128, blayout=row_major, slayout=none_box, fractal=512, pad=0>) {atomicType = #pto<atomic_type atomic_add>} | ||
| ``` | ||
|
|
||
| For a variable-size transfer, construct both partitions with the same runtime | ||
| extent and use dynamic staging valid dimensions when the extent may require a | ||
| partial final chunk: | ||
|
|
||
| ```mlir | ||
| %dst_part = pto.partition_view %dst_view, | ||
| offsets = [%c0, %c0], sizes = [%rows, %c4096] | ||
| : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %src_part = pto.partition_view %src_view, | ||
| offsets = [%c0, %c0], sizes = [%rows, %c4096] | ||
| : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %stage = pto.alloc_tile addr = %c0_i64 | ||
| valid_row = %c1 valid_col = %c4096 | ||
| : !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, | ||
| v_row=?, v_col=?, blayout=row_major, | ||
| slayout=none_box, fractal=512, pad=0> | ||
| pto.comm.tput(%dst_part, %src_part, buf(%stage) | ||
| : !pto.partition_tensor_view<?x4096xi8>, | ||
| !pto.partition_tensor_view<?x4096xi8>, | ||
| !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, | ||
| v_row=?, v_col=?, blayout=row_major, | ||
| slayout=none_box, fractal=512, pad=0>) | ||
| {atomicType = #pto<atomic_type atomic_none>} | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ##### `pto.comm.tget` - Synchronous Remote Read | ||
|
|
||
| **Summary:** Lowers to `pto::comm::TGET(...)` and copies data from remote GM to local GM through a VEC staging tile. | ||
| **Summary:** Copies data synchronously from remote GM to local GM through a VEC staging tile. | ||
|
|
||
| **Arguments:** | ||
|
|
||
|
|
@@ -10245,8 +10290,17 @@ pto.comm.tput(%dst, %src, buf(%ping, %pong) : !pto.partition_tensor_view<128xf32 | |
|
|
||
| **Constraints & Verification:** | ||
|
|
||
| - Same GM/global-like and staging constraints as `pto.comm.tput`. | ||
| - `dst` and `src` must have the same element type and static shape. | ||
| - The GM/global-like, dynamic partition, runtime extent, zero-length, and | ||
| staging constraints are the same as for `pto.comm.tput`. | ||
| - `dst` and `src` must have the same element type and identical static/dynamic | ||
| shape signatures. | ||
|
|
||
| **Semantics:** | ||
|
|
||
| For every logical index in the common `src` / `dst` shape, the operation reads | ||
| the remote `src` element and writes the corresponding local `dst` element. The | ||
| staging bundle may divide the logical range into chunks but does not change the | ||
| logical transfer extent. | ||
|
|
||
| **Examples:** | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3934,8 +3934,14 @@ static bool isCommGlobalLikeType(Type ty) { | |
| return isa<pto::TensorViewType, pto::PartitionTensorViewType>(ty); | ||
| } | ||
|
|
||
| static LogicalResult verifyCommGlobalLike(Operation *op, Value value, | ||
| StringRef name) { | ||
| enum class CommGlobalShapePolicy { | ||
| StaticOnly, | ||
| AllowDynamicPartitionView, | ||
| }; | ||
|
|
||
| static LogicalResult verifyCommGlobalLike( | ||
| Operation *op, Value value, StringRef name, | ||
| CommGlobalShapePolicy policy = CommGlobalShapePolicy::StaticOnly) { | ||
| Type ty = value.getType(); | ||
| if (!isCommGlobalLikeType(ty)) | ||
| return op->emitOpError() | ||
|
|
@@ -3944,10 +3950,23 @@ static LogicalResult verifyCommGlobalLike(Operation *op, Value value, | |
| SmallVector<int64_t, 4> shape = getShapeVec(ty); | ||
| if (shape.empty()) | ||
| return op->emitOpError() << "expects " << name << " to have rank >= 1"; | ||
|
|
||
| bool opAllowsDynamic = | ||
| policy == CommGlobalShapePolicy::AllowDynamicPartitionView; | ||
| bool isAllowedDynamicType = isa<pto::PartitionTensorViewType>(ty); | ||
| for (int64_t dim : shape) { | ||
| if (dim == ShapedType::kDynamic || dim <= 0) | ||
| return op->emitOpError() << "expects " << name | ||
| << " to have a positive static shape"; | ||
| if (dim == ShapedType::kDynamic) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Only the last one is safe, because pto-isa treats if (totalLogicalRows <= ubChunkRows && logicalDims[4] <= ubChunkCols) { TLOAD; ...; TSTORE_IMPL; return; }and it hands the tensors straight to TLOAD/TSTORE. Both PTO_ASSERT(validCol == gShape4, "The validCol of TileData must be equal to the 5th dim(Shape4) of ND shape!");
uint16_t nBurst = gShape3; // rows: from the tensor
uint32_t lenBurst = validCol * sizeof(typename TileData::DType); // columns: from the TILE
Failure scenario. The row dimension has none of this, because I compiled both of those shapes against this branch; they lower clean and emit To be fair this contract is pre-existing and unchecked for static shapes too -- Suggestion: restrict the relaxation to non-innermost dimensions. That covers every motivating case (pypto emits |
||
| if (!opAllowsDynamic) | ||
| return op->emitOpError() | ||
| << "does not support dynamic dimensions on " << name; | ||
| if (!isAllowedDynamicType) | ||
| return op->emitOpError() << "allows dynamic dimensions on " << name | ||
| << " only for partition_tensor_view"; | ||
| continue; | ||
| } | ||
| if (dim <= 0) | ||
| return op->emitOpError() << "expects every static dimension of " << name | ||
| << " to be positive"; | ||
| } | ||
| return success(); | ||
| } | ||
|
|
@@ -16299,32 +16318,42 @@ LogicalResult TGetAsyncOp::verify() { | |
| } | ||
|
|
||
| LogicalResult TPutOp::verify() { | ||
| if (failed(verifyCommGlobalLike(*this, getDst(), "dst")) || | ||
| failed(verifyCommGlobalLike(*this, getSrc(), "src")) || | ||
| if (failed(verifyCommGlobalLike( | ||
| *this, getDst(), "dst", | ||
| CommGlobalShapePolicy::AllowDynamicPartitionView)) || | ||
| failed(verifyCommGlobalLike( | ||
| *this, getSrc(), "src", | ||
| CommGlobalShapePolicy::AllowDynamicPartitionView)) || | ||
| failed(verifyCommStagingTileLike(*this, getPing(), "ping")) || | ||
| failed(verifyCommPingPongSameType(*this, getPing(), getPong(), "ping", | ||
| "pong"))) | ||
| return failure(); | ||
| if (getElemTy(getDst().getType()) != getElemTy(getSrc().getType())) | ||
| return emitOpError("expects src and dst to have the same element type"); | ||
| if (getShapeVec(getDst().getType()) != getShapeVec(getSrc().getType())) | ||
| return emitOpError("expects src and dst to have the same static shape"); | ||
| return emitOpError( | ||
| "expects src and dst to have the same static/dynamic shape signature"); | ||
| if (getElemTy(getPing().getType()) != getElemTy(getSrc().getType())) | ||
| return emitOpError("expects staging tile element type to match src/dst"); | ||
| return success(); | ||
| } | ||
|
|
||
| LogicalResult TGetOp::verify() { | ||
| if (failed(verifyCommGlobalLike(*this, getDst(), "dst")) || | ||
| failed(verifyCommGlobalLike(*this, getSrc(), "src")) || | ||
| if (failed(verifyCommGlobalLike( | ||
| *this, getDst(), "dst", | ||
| CommGlobalShapePolicy::AllowDynamicPartitionView)) || | ||
| failed(verifyCommGlobalLike( | ||
| *this, getSrc(), "src", | ||
| CommGlobalShapePolicy::AllowDynamicPartitionView)) || | ||
| failed(verifyCommStagingTileLike(*this, getPing(), "ping")) || | ||
| failed(verifyCommPingPongSameType(*this, getPing(), getPong(), "ping", | ||
| "pong"))) | ||
| return failure(); | ||
| if (getElemTy(getDst().getType()) != getElemTy(getSrc().getType())) | ||
| return emitOpError("expects src and dst to have the same element type"); | ||
| if (getShapeVec(getDst().getType()) != getShapeVec(getSrc().getType())) | ||
| return emitOpError("expects src and dst to have the same static shape"); | ||
| return emitOpError( | ||
| "expects src and dst to have the same static/dynamic shape signature"); | ||
| if (getElemTy(getPing().getType()) != getElemTy(getSrc().getType())) | ||
| return emitOpError("expects staging tile element type to match src/dst"); | ||
| return success(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| // This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| // CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| // Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| // See LICENSE in the root of the software repository for the full text of the License. | ||
|
|
||
| // RUN: not ptoas --pto-arch=a3 --emit-pto-ir %s 2>&1 | FileCheck %s | ||
|
|
||
| module { | ||
| func.func @dynamic_async_p2p( | ||
| %dst: !pto.partition_tensor_view<?xf32>, | ||
| %src: !pto.partition_tensor_view<?xf32>, | ||
| %session: !pto.async_session) { | ||
| %event = pto.comm.tput_async(%dst, %src, %session : !pto.partition_tensor_view<?xf32>, !pto.partition_tensor_view<?xf32>, !pto.async_session) -> !pto.async_event | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // CHECK: error: 'pto.comm.tput_async' op expects dst to have a static shape |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| // This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| // CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| // Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| // See LICENSE in the root of the software repository for the full text of the License. | ||
|
|
||
| // RUN: not ptoas --pto-arch=a3 --emit-pto-ir %s 2>&1 | FileCheck %s | ||
|
|
||
| module { | ||
| func.func @dynamic_collective( | ||
| %src: !pto.partition_tensor_view<?x128xf32>, | ||
| %peer: !pto.partition_tensor_view<?x128xf32>, | ||
| %stage: !pto.tile_buf<loc=vec, dtype=f32, rows=1, cols=128, v_row=1, v_col=128, blayout=row_major, slayout=none_box, fractal=512, pad=0>) { | ||
| pto.comm.tbroadcast(%src, recv(%stage), group(%peer) : !pto.partition_tensor_view<?x128xf32>, !pto.tile_buf<loc=vec, dtype=f32, rows=1, cols=128, v_row=1, v_col=128, blayout=row_major, slayout=none_box, fractal=512, pad=0>, !pto.partition_tensor_view<?x128xf32>) {root = 0 : i32} | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // CHECK: error: 'pto.comm.tbroadcast' op does not support dynamic dimensions on src |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| // This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| // CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| // Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| // See LICENSE in the root of the software repository for the full text of the License. | ||
|
|
||
| // RUN: not ptoas --pto-arch=a3 --emit-pto-ir %s 2>&1 | FileCheck %s | ||
|
|
||
| module { | ||
| func.func @dynamic_signal( | ||
| %signal: !pto.partition_tensor_view<?xi32>, %value: i32) { | ||
| pto.comm.tnotify(%signal, %value : !pto.partition_tensor_view<?xi32>, i32) {notifyOp = #pto<notify_op set>} | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // CHECK: error: 'pto.comm.tnotify' op does not support dynamic dimensions on signal |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| // This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| // CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| // Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| // See LICENSE in the root of the software repository for the full text of the License. | ||
|
|
||
| // RUN: ptoas --pto-arch=a3 --pto-level=level3 %s -o - 2>&1 | FileCheck %s --check-prefix=EMITC | ||
| // RUN: ptoas --pto-arch=a3 --pto-level=level3 --mlir-print-ir-after=pto-resolve-buffer-select %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=NATIVE | ||
|
|
||
| module { | ||
| func.func @comm_p2p_dynamic_partition( | ||
| %dst_ptr: !pto.ptr<i8>, %src_ptr: !pto.ptr<i8>, %runtime_rows: i32) { | ||
| %c0_i64 = arith.constant 0 : i64 | ||
| %c0 = arith.constant 0 : index | ||
| %c1 = arith.constant 1 : index | ||
| %c32 = arith.constant 32 : index | ||
| %c4096 = arith.constant 4096 : index | ||
| %rows = arith.index_cast %runtime_rows : i32 to index | ||
| %dst_view = pto.make_tensor_view %dst_ptr, shape = [%c32, %c4096], strides = [%c4096, %c1] {layout = #pto.layout<nd>} : !pto.tensor_view<?x?xi8> | ||
| %src_view = pto.make_tensor_view %src_ptr, shape = [%c32, %c4096], strides = [%c4096, %c1] {layout = #pto.layout<nd>} : !pto.tensor_view<?x?xi8> | ||
| %dst = pto.partition_view %dst_view, offsets = [%c0, %c0], sizes = [%rows, %c4096] : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %src = pto.partition_view %src_view, offsets = [%c0, %c0], sizes = [%rows, %c4096] : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %stage = pto.alloc_tile addr = %c0_i64 valid_row = %c1 valid_col = %c4096 : !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=?, v_col=?, blayout=row_major, slayout=none_box, fractal=512, pad=0> | ||
| pto.comm.tput(%dst, %src, buf(%stage) : !pto.partition_tensor_view<?x4096xi8>, !pto.partition_tensor_view<?x4096xi8>, !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=?, v_col=?, blayout=row_major, slayout=none_box, fractal=512, pad=0>) {atomicType = #pto<atomic_type atomic_none>} | ||
| pto.comm.tget(%dst, %src, buf(%stage) : !pto.partition_tensor_view<?x4096xi8>, !pto.partition_tensor_view<?x4096xi8>, !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=?, v_col=?, blayout=row_major, slayout=none_box, fractal=512, pad=0>) | ||
| return | ||
| } | ||
|
|
||
| // A static valid shape remains legal. At runtime its row/column values must | ||
| // divide the transfer shape whenever the transfer enters the chunked path. | ||
| func.func @comm_p2p_dynamic_partition_static_valid( | ||
| %dst_ptr: !pto.ptr<i8>, %src_ptr: !pto.ptr<i8>, %runtime_rows: i32) { | ||
| %c0_i64 = arith.constant 0 : i64 | ||
| %c0 = arith.constant 0 : index | ||
| %c1 = arith.constant 1 : index | ||
| %c32 = arith.constant 32 : index | ||
| %c4096 = arith.constant 4096 : index | ||
| %rows = arith.index_cast %runtime_rows : i32 to index | ||
| %dst_view = pto.make_tensor_view %dst_ptr, shape = [%c32, %c4096], strides = [%c4096, %c1] {layout = #pto.layout<nd>} : !pto.tensor_view<?x?xi8> | ||
| %src_view = pto.make_tensor_view %src_ptr, shape = [%c32, %c4096], strides = [%c4096, %c1] {layout = #pto.layout<nd>} : !pto.tensor_view<?x?xi8> | ||
| %dst = pto.partition_view %dst_view, offsets = [%c0, %c0], sizes = [%rows, %c4096] : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %src = pto.partition_view %src_view, offsets = [%c0, %c0], sizes = [%rows, %c4096] : !pto.tensor_view<?x?xi8> -> !pto.partition_tensor_view<?x4096xi8> | ||
| %stage = pto.alloc_tile addr = %c0_i64 : !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=1, v_col=4096, blayout=row_major, slayout=none_box, fractal=512, pad=0> | ||
| pto.comm.tput(%dst, %src, buf(%stage) : !pto.partition_tensor_view<?x4096xi8>, !pto.partition_tensor_view<?x4096xi8>, !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=1, v_col=4096, blayout=row_major, slayout=none_box, fractal=512, pad=0>) {atomicType = #pto<atomic_type atomic_none>} | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // EMITC: pto::Shape<1, 1, 1, -1, 4096> | ||
| // EMITC-SAME: ({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^)]+}}) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Five I proved that by mutation. In Rebuilt and re-ran this file: still passes. A compiler that silently moved nothing at all would ship green. The NATIVE block does pin Separately: both the EMITC and NATIVE blocks are satisfied entirely by |
||
| // EMITC: pto::Stride<-1, -1, -1, -1, -1> | ||
| // EMITC-SAME: ({{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^,]+}}, {{[^)]+}}) | ||
| // EMITC: GlobalTensor<int8_t, pto::Shape<1, 1, 1, -1, 4096>, pto::Stride<-1, -1, -1, -1, -1>, pto::Layout::ND> | ||
| // EMITC: pto::comm::TPUT( | ||
| // EMITC: pto::comm::TGET( | ||
|
|
||
| // NATIVE: IR Dump After PTOResolveBufferSelect | ||
| // NATIVE-LABEL: func.func @comm_p2p_dynamic_partition | ||
| // NATIVE: %[[ROWS:.*]] = arith.index_cast | ||
| // NATIVE: %[[DST:.*]] = pto.partition_view {{.*}} sizes = [%[[ROWS]], %c4096] | ||
| // NATIVE: %[[SRC:.*]] = pto.partition_view {{.*}} sizes = [%[[ROWS]], %c4096] | ||
| // NATIVE: pto.comm.tput(%[[DST]], %[[SRC]], buf( | ||
| // NATIVE-SAME: !pto.partition_tensor_view<?x4096xi8> | ||
| // NATIVE: pto.comm.tget(%[[DST]], %[[SRC]], buf( | ||
| // NATIVE-SAME: !pto.partition_tensor_view<?x4096xi8> | ||
| // NATIVE-NOT: memref.subview | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| // This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| // CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| // Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| // See LICENSE in the root of the software repository for the full text of the License. | ||
|
|
||
| // RUN: not ptoas --pto-arch=a3 --emit-pto-ir %s 2>&1 | FileCheck %s | ||
|
|
||
| module { | ||
| func.func @shape_signature_mismatch( | ||
| %dst: !pto.partition_tensor_view<?x4096xi8>, | ||
| %src: !pto.partition_tensor_view<?x2048xi8>, | ||
| %stage: !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=1, v_col=4096, blayout=row_major, slayout=none_box, fractal=512, pad=0>) { | ||
| pto.comm.tput(%dst, %src, buf(%stage) : !pto.partition_tensor_view<?x4096xi8>, !pto.partition_tensor_view<?x2048xi8>, !pto.tile_buf<loc=vec, dtype=i8, rows=1, cols=4096, v_row=1, v_col=4096, blayout=row_major, slayout=none_box, fractal=512, pad=0>) {atomicType = #pto<atomic_type atomic_none>} | ||
| return | ||
| } | ||
| } | ||
|
|
||
| // CHECK: error: 'pto.comm.tput' op expects src and dst to have the same static/dynamic shape signature |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirming Codex's P2 with a reproduction on this branch -- a constant zero extent is rejected before it can reach
tput:PartitionViewOp::verify(lib/PTO/IR/PTO.cpp:2531) rejects any constant size<= 0, so only a runtime SSA value that happens to be zero ever reachesTPUT_IMPL'stotalLogicalRows == 0early return.The corollary worries me more than the wording:
getConstIndexValuesees through folded constants, so a program that is legal at parse time hard-fails partition_view verification if a later pass constant-folds the size operand to0-- for example after inlining a caller that specializes the peer count to zero. Either relax the check to< 0when the corresponding result dim is dynamic, or drop the zero-extent claim from the manual.