Skip to content
Closed
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
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

cmake_minimum_required(VERSION 3.20.0)

include(cmake/fetch_cann_cmake.cmake)

# CANN/Ascend CMake packages used by downstream PTOAS builds may still use the
# pre-CMake-3.30 FetchContent_Populate(<declared-name>) pattern. Keep that
# compatibility path enabled so CMake 4.x developer warnings do not become
Expand All @@ -29,6 +27,8 @@ if(POLICY CMP0175)
set(CMAKE_POLICY_DEFAULT_CMP0175 OLD)
endif()

include(cmake/fetch_cann_cmake.cmake)

# Standard Python build backends pass environment variables through to CMake
# but do not synthesize project-specific cache arguments. Accept the existing
# LLVM_BUILD_DIR convention directly so `pip wheel .` and `pip install .` can
Expand Down
9 changes: 7 additions & 2 deletions cmake/fetch_cann_cmake.cmake
Original file line number Diff line number Diff line change
@@ -1,14 +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.
# -----------------------------------------------------------------------------------------------------------

if(NOT PROJECT_SOURCE_DIR)
# Standalone builds may configure without a pre-seeded CANN third-party
# directory (e.g. CI). Keep FetchContent's declared SOURCE_DIR inside the
# writable CMake binary tree instead of resolving an empty variable to the
# filesystem root. Script-mode packaging still requires an explicit path.
if(NOT CANN_3RD_LIB_PATH AND CMAKE_BINARY_DIR)
set(CANN_3RD_LIB_PATH "${CMAKE_BINARY_DIR}/cann-3rd-lib")
endif()
# Temporary test pin for cann/cmake MR !277. Revert this URL/ref pair
# after validation and switch to the released cann/cmake tag once MR !277
# is merged.
Expand Down
5 changes: 2 additions & 3 deletions docs/isa/vmi-isa/06-convert.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
| Attribute | Values | Valid for | Description |
|---|---|---|---|
| `rounding` | `"R"` (nearest-even), `"A"` (away-from-zero), `"H"` (half-up), `"Z"` (toward-zero); for the `bf16x2→f4x2` contract pair the allowed set is `"R"`,`"A"`,`"F"` (floor), `"C"` (ceil), `"Z"` (toward-zero) — `"H"` is **rejected** | fp narrowing | Rounding mode |
| `saturate` | `"SAT"`, `"NOSAT"` | required for fp-narrow / int-narrow; for fp→si / fp→ui the requirement follows the vcvt contract's `requiresSat` (e.g. `f16→s8` required, `f16→s32` **forbidden** — no overflow possible; same-width `bf16→f16` required, same-width `f16→bf16` **forbidden**); the `bf16x2→f4x2` narrow has `requiresSat=false` — any `saturate` is **forbidden** | `SAT` clamps to ±max of the destination type; `NOSAT` performs a direct bit truncation of the result representation. |
| `saturate` | `"SAT"`, `"NOSAT"` | required for fp-narrow / int-narrow; for fp→si / fp→ui the requirement follows the vcvt contract's `requiresSat` (e.g. `f16→s8` required, `f16→s32` **forbidden** — no overflow possible; same-width `bf16→f16` required, same-width `f16→bf16` **forbidden**); the `bf16x2→f4x2` narrow has `requiresSat=false` — any `saturate` is **forbidden** | For signed destinations, `SAT` clamps to `[min, max]`; for unsigned or signless destinations, it clamps to `[0, max]`. `NOSAT` performs a direct bit truncation of the result representation. |

- **datatypes:** Source and destination from `{f32, f16, bf16, fp8_e4m3, fp8_e5m2, i32, i16, i8, ui32, ui16, ui8}`; packed carrier types `{!pto.bf16x2, !pto.f4E1M2x2, !pto.f4E2M1x2}` for the bf16x2↔f4x2 fp-to-fp pair (see contract `lookupVMIFpToFpContract`). `bf16x2` is **conversion-only** — it may not appear as a compute element type (`vfadd`/`vfmul`/`vcmp`/...).
- **datatypes:** Source and destination from `{f32, f16, bf16, fp8_e4m3, fp8_e5m2, i32, i16, i8, si32, si16, si8, ui32, ui16, ui8}`; packed carrier types `{!pto.bf16x2, !pto.f4E1M2x2, !pto.f4E2M1x2}` for the bf16x2↔f4x2 fp-to-fp pair (see contract `lookupVMIFpToFpContract`). `bf16x2` is **conversion-only** — it may not appear as a compute element type (`vfadd`/`vfmul`/`vcmp`/...). Signless `iN` is treated as unsigned; use `siN` for signed conversion semantics.
- **lowering to `pto.mi`:**

| Conversion | Physical lowering | `#mi` | `dep` |
Expand Down Expand Up @@ -128,7 +128,6 @@
- **notes:**
- `vcvt` **does not change lane count** — `src.L == dst.L` always. The
physical register count `K` changes because `bitwidth(T)` changes.
- Integer signedness is determined by the **element type**.
- The `part`/`parity`/`width` axes are lowering-only; the user never writes
`EVEN`/`ODD`/`P0..P3`.
- Radix-4 (8↔32) is **not** a stacked predicate chain and **not** a UB
Expand Down
30 changes: 30 additions & 0 deletions lib/PTO/Transforms/VMILayoutAssignment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TypeSwitch.h"

#include <type_traits>

namespace mlir {
namespace pto {
#define GEN_PASS_DEF_VMILAYOUTASSIGNMENT
Expand Down Expand Up @@ -693,6 +695,34 @@ struct LayoutSolver {
WalkResult addExtensionConstraint(CastOp castOp, Operation *op) {
auto sourceType = cast<VMIVRegType>(castOp.getSource().getType());
auto resultType = cast<VMIVRegType>(castOp.getResult().getType());

// A four-lane byte/halfword -> ui32 widening is a compact group-slot
// operation. Seed the result with the group-slot carrier so propagation
// selects the existing group-slot extension lowering (and avoids creating
// an unsupported group-slot -> dense lane-stride ensure_layout).
if constexpr (std::is_same_v<CastOp, VMIExtUIOp>) {
auto sourceInteger = dyn_cast<IntegerType>(sourceType.getElementType());
auto resultInteger = dyn_cast<IntegerType>(resultType.getElementType());
unsigned sourceBits =
pto::getPTOStorageElemBitWidth(sourceType.getElementType());
unsigned resultBits =
pto::getPTOStorageElemBitWidth(resultType.getElementType());
bool compactUI32Widen =
sourceType.getElementCount() == 4 && sourceInteger && resultInteger &&
!sourceType.getLayoutAttr() && !resultType.getLayoutAttr() &&
(resultInteger.isUnsigned() || resultInteger.isSignless()) &&
(sourceBits == 8 || sourceBits == 16) &&
resultBits == 32;
if (compactUI32Widen) {
VMILayoutAttr compactLayout =
VMILayoutAttr::getGroupSlots(ctx, /*numGroups=*/4,
/*slots=*/mlir::pto::kValue8);
return *constraintResult(setPreferredLayout(
castOp.getResult(), compactLayout, op,
DataLayoutSeedPhase::CompactCast));
}
}

FailureOr<VMICastLayoutFact> fact =
VMILayoutSupport().getPreferredCastLayoutFact(sourceType, resultType);
if (failed(fact)) {
Expand Down
19 changes: 13 additions & 6 deletions packaging/ptoas-vmi/pyproject.toml.patch
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
diff --git a/pyproject.toml b/pyproject.toml
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,7 +18,7 @@ build-backend = "scikit_build_core.build"
@@ -16,11 +16,11 @@
build-backend = "scikit_build_core.build"

[project]
-name = "ptoas"
-dynamic = ["version"]
Expand All @@ -10,20 +12,25 @@ diff --git a/pyproject.toml b/pyproject.toml
+version = "0.1.6"
+description = "PTO Assembler & Optimizer with VMI support"
readme = "README.md"
requires-python = ">=3.10"
-requires-python = ">=3.7"
+requires-python = ">=3.10"
license = "Apache-2.0"
@@ -43,4 +43,5 @@ cmake.version = "CMakeLists.txt"
dependencies = [
"numpy",
@@ -43,6 +43,7 @@
ninja.version = ">=1.10"
build.verbose = false
editable.mode = "redirect"
+sdist.inclusion-mode = "manual"
install.components = ["PTOAS_Python"]
@@ -53,3 +54,4 @@ TileOps = "lib/TileOps"

[tool.scikit-build.wheel.packages]
@@ -53,8 +54,5 @@

[tool.scikit-build.cmake.define]
PTOAS_RELEASE_VERSION_OVERRIDE = { env = "PTOAS_RELEASE_VERSION_OVERRIDE", default = "" }
+PTOAS_CLI_VERSION_LABEL = "vmi"

@@ -56,4 +58,0 @@ PTOAS_RELEASE_VERSION_OVERRIDE = { env = "PTOAS_RELEASE_VERSION_OVERRIDE", default = "" }

-[tool.scikit-build.metadata.version]
-provider = "scikit_build_core.metadata.regex"
-input = "CMakeLists.txt"
Expand Down
4 changes: 2 additions & 2 deletions ptodsl/docs/user_guide/14-vmi-virtual-instruction-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -881,8 +881,8 @@ group_max = pto.vmi.vcmax(
Converts the element type of `source` to the target element type. PTODSL
infers the result vector type from the source lane count/layout and `to_dtype`.

For int→int widening, the source element type must carry signedness
(e.g. `si8`/`ui8`/`si16`/`ui16`); signless integers are rejected.
For `vcvt`, signless integer types (`i8`/`i16`/`i32`) are treated as
unsigned. Use `siN` types for signed conversion semantics.

**Parameters**:

Expand Down
56 changes: 56 additions & 0 deletions test/lit/vmi_new/vmi_to_vpto_extui_compact_vl4.pto
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 the 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 OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and
// limitations under the License. See LICENSE in the root of the software repository
// for the full text of the License.

// RUN: pto-test-opt %s -vmi-lower-unified-to-legacy -vmi-mask-granularity-assignment -vmi-layout-assignment | FileCheck %s --check-prefix=ASSIGN
// RUN: pto-test-opt %s -vmi-lower-unified-to-legacy -vmi-mask-granularity-assignment -vmi-layout-assignment -vmi-to-vpto | FileCheck %s --check-prefix=LOWER

module {
func.func @extui_compact_vl4(
%src: !pto.ptr<i8, ub>, %dst: !pto.ptr<ui32, ub>, %off: index) {
%c1 = arith.constant 1 : index
%value = pto.vmi.vload %src[%off], %c1 {group = 4}
: !pto.ptr<i8, ub> -> !pto.vmi.vreg<4xi8>
%wide = pto.vmi.vcvt %value
: !pto.vmi.vreg<4xi8> -> !pto.vmi.vreg<4xui32>
pto.vmi.vstore %wide, %dst[%off], %c1 {group = 4}
: !pto.vmi.vreg<4xui32>, !pto.ptr<ui32, ub>
return
}

func.func @extui_compact_vl4_i16(
%src: !pto.ptr<i16, ub>, %dst: !pto.ptr<ui32, ub>, %off: index) {
%c1 = arith.constant 1 : index
%value = pto.vmi.vload %src[%off], %c1 {group = 4}
: !pto.ptr<i16, ub> -> !pto.vmi.vreg<4xi16>
%wide = pto.vmi.vcvt %value
: !pto.vmi.vreg<4xi16> -> !pto.vmi.vreg<4xui32>
pto.vmi.vstore %wide, %dst[%off], %c1 {group = 4}
: !pto.vmi.vreg<4xui32>, !pto.ptr<ui32, ub>
return
}
}

// ASSIGN-LABEL: func.func @extui_compact_vl4(
// ASSIGN: %[[WIDE:.*]] = pto.vmi.extui %{{.*}} : !pto.vmi.vreg<4xi8, #pto.vmi.layout<num_groups = 4, slots = 8>> -> !pto.vmi.vreg<4xui32, #pto.vmi.layout<num_groups = 4, slots = 8>>

// ASSIGN-LABEL: func.func @extui_compact_vl4_i16(
// ASSIGN: %[[WIDE16:.*]] = pto.vmi.extui %{{.*}} : !pto.vmi.vreg<4xi16, #pto.vmi.layout<num_groups = 4, slots = 8>> -> !pto.vmi.vreg<4xui32, #pto.vmi.layout<num_groups = 4, slots = 8>>

// LOWER-LABEL: func.func @extui_compact_vl4(
// LOWER-COUNT-2: pto.vzunpack
// LOWER: pto.vstus
// LOWER-NOT: pto.vmi.
// LOWER-NOT: unrealized_conversion_cast

// LOWER-LABEL: func.func @extui_compact_vl4_i16(
// LOWER: pto.vzunpack
// LOWER: pto.vstus
// LOWER-NOT: pto.vmi.
// LOWER-NOT: unrealized_conversion_cast
Loading