Skip to content
Open
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
406 changes: 406 additions & 0 deletions docs/designs/vpto-tied-copy-materialization-design-zh.md

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion docs/isa/micro-isa/06-unary-vector-ops.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ Element-wise operations that take one vector input and produce one vector output
## Common Operand Model

- `%input` is the source vector register value.
- `%mask` is the predicate operand. For this family, inactive lanes follow the
- `%mask`, where present, is the predicate operand. Inactive lanes follow the
predication behavior of the selected instruction form: zeroing forms
zero-fill inactive lanes, while merging forms preserve the destination value.
`pto.vmov` is the exception in this group: it has no mask and copies every
lane.
- `%result` is the destination vector register value. Unless stated otherwise,
`%result` has the same lane count and element type as `%input`.

Expand Down Expand Up @@ -161,6 +163,26 @@ for (int i = 0; i < N; i++)

## Movement

### `pto.vmov`

- **syntax:** `%result = pto.vmov %input : !pto.vreg<NxT> -> !pto.vreg<NxT>`
- **A5 types:** ui8, si8, ui16, si16, f16, bf16, ui32, si32, f32,
si64

```c
for (int i = 0; i < N; i++)
dst[i] = src[i];
```

- **inputs:** `%input` supplies every lane of one physical vector register.
- **outputs:** `%result` contains the same lane values in an independent
physical vector register.
- **constraints and limitations:** Source and result types MUST match and MUST
represent one full A5 vector register. This operation has no mask: it always
copies the complete register. It represents a required hardware copy and is
therefore not removed or merged with another `pto.vmov`, even when the two
operations have the same input.

## Typical Usage

```mlir
Expand Down
3 changes: 2 additions & 1 deletion docs/vpto-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ This section provides a categorized overview of all PTO micro Instruction operat
| 3 | [Vector Load/Store](isa/micro-isa/03-vector-load-store.md) | UB↔vreg data movement with various access patterns | ~23 | `pto.vlds`, `pto.vldsx2`, `pto.vgather2`, `pto.vsts`, `pto.vstsx2`, `pto.vscatter`, `pto.sprclr`, `pto.sprsti`, `pto.sprsts`, etc. |
| 4 | [Predicate Load/Store](isa/micro-isa/04-predicate-load-store.md) | UB↔mask register movement | 5 | `pto.plds`, `pto.pldi`, `pto.psts`, `pto.psti`, `pto.pstu` |
| 5 | [Materialization & Predicate Ops](isa/micro-isa/05-materialization-predicate.md) | Scalar broadcast, predicate generation and manipulation | ~20 | `pto.vbr`, `pto.vdup`, `pto.pset_b*`, `pto.pge_b*`, `pto.plt_b*`, `pto.pltm_b*`, `pto.ppack`, `pto.punpack`, `pto.pnot`, `pto.psel`, etc. |
| 6 | [Unary Vector Ops](isa/micro-isa/06-unary-vector-ops.md) | Single-input element-wise operations | 7 | `pto.vabs`, `pto.vneg`, `pto.vexp`, `pto.vln`, `pto.vsqrt`, `pto.vrelu`, `pto.vnot` |
| 6 | [Unary Vector Ops](isa/micro-isa/06-unary-vector-ops.md) | Single-input element-wise and register-copy operations | 8 | `pto.vabs`, `pto.vneg`, `pto.vexp`, `pto.vln`, `pto.vsqrt`, `pto.vrelu`, `pto.vnot`, `pto.vmov` |
| 7 | [Binary Vector Ops](isa/micro-isa/07-binary-vector-ops.md) | Two-input element-wise operations | 14 | `pto.vadd`, `pto.vsub`, `pto.vmul`, `pto.vdiv`, `pto.vmax`, `pto.vmin`, `pto.vmadd`, `pto.vand`, `pto.vor`, `pto.vxor`, `pto.vshl`, `pto.vshr`, `pto.vaddc`, `pto.vsubc` |
| 8 | [Vec-Scalar Ops](isa/micro-isa/08-vec-scalar-ops.md) | Vector-scalar operations | 9 | `pto.vadds`, `pto.vmuls`, `pto.vmaxs`, `pto.vmins`, `pto.vlrelu`, `pto.vshls`, `pto.vshrs`, `pto.vaddcs`, `pto.vsubcs` |
| 9 | [Conversion Ops](isa/micro-isa/09-conversion-ops.md) | Type conversion with rounding/saturation control | 4 | `pto.vcvt`, `pto.vtrc`, `pto.vbitcast`, `pto.pbitcast` |
Expand Down Expand Up @@ -1379,6 +1379,7 @@ This section provides a categorized overview of all PTO micro Instruction operat
| Operation | Group | Description |
|-----------|-------|-------------|
| Type Conversion | 9 | `pto.vcvt`, `pto.vbitcast`, `pto.pbitcast` |
| Full vector-register copy | 6 | `pto.vmov` |
| Interleave/Deinterleave | 12 | `pto.vintlv`, `pto.vdintlv` |
| Interleave/Deinterleave (not A5) | 12 | `pto.vintlvv2`, `pto.vdintlvv2` |

Expand Down
19 changes: 19 additions & 0 deletions include/PTO/IR/VPTOInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@ def VPTOSchedulingOpInterface : OpInterface<"VPTOSchedulingOpInterface"> {
];
}

def VPTOTiedOperandOpInterface
: OpInterface<"VPTOTiedOperandOpInterface"> {
let description = [{
Describes one operation-local physical register constraint where a result
must reuse and overwrite one operand's register. Copy materialization and
scheduling policy are consumers of this fact and are not part of the
interface contract.
}];
let cppNamespace = "::mlir::pto";
let methods = [
InterfaceMethod<
"Return the operand index whose physical register is reused.",
"unsigned", "getTiedOperandIndex">,
InterfaceMethod<
"Return the result index tied to the operand.",
"unsigned", "getTiedResultIndex">
];
}

def PTO_MadSemanticOpInterface : OpInterface<"MadSemanticOpInterface"> {
let description = [{
Interface for semantic MAD-family ops. The interface is only a uniform view
Expand Down
47 changes: 41 additions & 6 deletions include/PTO/IR/VPTOOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2340,7 +2340,11 @@ def PTO_VcgmaxOp : PTO_UnaryVecOp<"vcgmax">;
def PTO_VcgminOp : PTO_UnaryVecOp<"vcgmin">;
def PTO_VcpaddOp : PTO_UnaryVecOp<"vcpadd">;

class PTO_HistogramOp<string mnemonic> : PTO_VectorMicroOp<mnemonic, [Pure]> {
class PTO_HistogramOp<string mnemonic>
: PTO_VectorMicroOp<mnemonic, [
Pure,
DeclareOpInterfaceMethods<VPTOTiedOperandOpInterface>
]> {
let arguments = (ins
PTO_VectorType:$acc,
PTO_VectorType:$source,
Expand Down Expand Up @@ -2405,7 +2409,8 @@ def PTO_VandOp : PTO_BinaryVecOp<"vand">;
def PTO_VorOp : PTO_BinaryVecOp<"vor">;
def PTO_VxorOp : PTO_BinaryVecOp<"vxor">;

class PTO_TernaryVecOp<string mnemonic> : PTO_VectorMicroOp<mnemonic, [Pure]> {
class PTO_TernaryVecOp<string mnemonic, list<Trait> traits = []>
: PTO_VectorMicroOp<mnemonic, !listconcat([Pure], traits)> {
let arguments = (ins
PTO_VectorType:$acc,
PTO_VectorType:$lhs,
Expand All @@ -2421,7 +2426,9 @@ class PTO_TernaryVecOp<string mnemonic> : PTO_VectorMicroOp<mnemonic, [Pure]> {
}];
}

def PTO_VmaddOp : PTO_TernaryVecOp<"vmadd">;
def PTO_VmaddOp : PTO_TernaryVecOp<"vmadd", [
DeclareOpInterfaceMethods<VPTOTiedOperandOpInterface>
]>;

def PTO_VaddcOp : PTO_VectorMicroOp<"vaddc", [Pure]> {
let arguments = (ins
Expand Down Expand Up @@ -2666,6 +2673,25 @@ def PTO_VbitcastOp : PTO_VectorMicroOp<"vbitcast", [Pure]> {
}];
}

def PTO_VmovOp : PTO_VectorMicroOp<"vmov", []> {
let summary = "Materialized full physical vector-register copy";
let description = [{
Copies all lanes of one physical vector register into an independent
destination register. The operation is intentionally not Pure: two copies
of the same input represent distinct physical registers and must not be
folded, merged, or removed.
}];

let arguments = (ins PTO_VectorType:$input);
let results = (outs PTO_VectorType:$result);

let hasVerifier = 1;

let assemblyFormat = [{
$input attr-dict `:` type($input) `->` type($result)
}];
}

def PTO_VciOp : PTO_VectorMicroOp<"vci", [Pure]> {
let arguments = (ins
AnyTypeOf<[AnyInteger, AnyFloat], "integer/float scalar">:$index,
Expand Down Expand Up @@ -3407,7 +3433,10 @@ def PTO_VselrOp : PTO_VectorMicroOp<"vselr", [Pure]> {

def PTO_VsqzOp : PTO_UnaryVecOp<"vsqz">;

def PTO_VusqzOp : PTO_VectorMicroOp<"vusqz", [Pure]> {
def PTO_VusqzOp : PTO_VectorMicroOp<"vusqz", [
Pure,
DeclareOpInterfaceMethods<VPTOTiedOperandOpInterface>
]> {
let arguments = (ins
PTO_VectorType:$src,
PTO_MaskTypeConstraint:$mask
Expand Down Expand Up @@ -3550,7 +3579,10 @@ def PTO_VmullOp : PTO_VectorMicroOp<"vmull", [Pure]> {
}];
}

def PTO_VmulaOp : PTO_VectorMicroOp<"vmula", [Pure]> {
def PTO_VmulaOp : PTO_VectorMicroOp<"vmula", [
Pure,
DeclareOpInterfaceMethods<VPTOTiedOperandOpInterface>
]> {
let arguments = (ins
PTO_VectorType:$acc,
PTO_VectorType:$lhs,
Expand Down Expand Up @@ -3614,7 +3646,10 @@ def PTO_VexpdifOp : PTO_VectorMicroOp<"vexpdif", [Pure]> {
}];
}

def PTO_VaxpyOp : PTO_VectorMicroOp<"vaxpy", [Pure]> {
def PTO_VaxpyOp : PTO_VectorMicroOp<"vaxpy", [
Pure,
DeclareOpInterfaceMethods<VPTOTiedOperandOpInterface>
]> {
let arguments = (ins
PTO_VectorType:$src0,
PTO_VectorType:$src1,
Expand Down
34 changes: 34 additions & 0 deletions include/PTO/IR/VPTOPhysicalRegister.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

//===- VPTOPhysicalRegister.h - VPTO physical register views ---*- C++ -*-===//
//
// This file defines scheduler-independent helpers for identifying SSA values
// that are zero-cost views of the same VPTO physical register.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_DIALECT_PTO_IR_VPTOPHYSICALREGISTER_H
#define MLIR_DIALECT_PTO_IR_VPTOPHYSICALREGISTER_H

#include "mlir/IR/Operation.h"
#include "mlir/IR/Value.h"

namespace mlir::pto {

/// Return true when `op` only changes the SSA type view of one physical vector
/// or predicate register.
bool isPhysicalRegisterView(Operation *op);

/// Follow zero-cost physical-register views to their shared SSA root. A real
/// copy such as pto.vmov always starts a new root.
Value getPhysicalRegisterViewRoot(Value value);

} // namespace mlir::pto

#endif // MLIR_DIALECT_PTO_IR_VPTOPHYSICALREGISTER_H
1 change: 1 addition & 0 deletions include/PTO/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ std::unique_ptr<Pass> createVPTOPtrCastCleanupPass();
std::unique_ptr<Pass> createVPTOCombineReductionsPass();
std::unique_ptr<Pass> createVPTOOptimizeVcvtPass();
std::unique_ptr<Pass> createVPTOMaskSimplifyPass();
std::unique_ptr<Pass> createVPTOMaterializeTiedOperandCopiesPass();
std::unique_ptr<Pass>
createVPTOSchedulerPass(const VPTOSchedulerOptions &options = {});
LogicalResult validateVPTOAuthoringIR(ModuleOp module,
Expand Down
17 changes: 17 additions & 0 deletions include/PTO/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,23 @@ def PTOValidateVPTOEmissionIR
"mlir::scf::SCFDialect"];
}

def VPTOMaterializeTiedOperandCopies
: Pass<"pto-vpto-materialize-tied-operand-copies", "func::FuncOp"> {
let summary = "Materialize physical copies for destructive VPTO tied operands";
let description = [{
Finds A5 vector operations whose result must reuse one input physical
register. For each block-local physical-view root, the last destructive
material use may update the original register; all other destructive uses
receive an explicit full-register `pto.vmov` copy. Cross-block, live-out,
and later ordinary reads use the conservative all-copy form. The pass is
independent of the VPTO scheduler and is idempotent.
}];
let constructor =
"mlir::pto::createVPTOMaterializeTiedOperandCopiesPass()";
let dependentDialects = ["mlir::func::FuncDialect",
"mlir::pto::PTODialect"];
}

def VPTOScheduler : Pass<"pto-vpto-scheduler", "ModuleOp"> {
let summary = "Analyze emission-ready VPTO scheduling regions";
let description = [{
Expand Down
1 change: 1 addition & 0 deletions lib/PTO/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_mlir_dialect_library(PTOIR
PTO.cpp
VPTO.cpp
VPTOAddressSemantics.cpp
VPTOPhysicalRegister.cpp
VPTOScheduling.cpp
VMI.cpp
VPTOUbOps.cpp
Expand Down
48 changes: 48 additions & 0 deletions lib/PTO/IR/VPTO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@
using namespace mlir;
using namespace mlir::pto;

unsigned Chistv2Op::getTiedOperandIndex() { return 0; }
unsigned Chistv2Op::getTiedResultIndex() { return 0; }
unsigned Dhistv2Op::getTiedOperandIndex() { return 0; }
unsigned Dhistv2Op::getTiedResultIndex() { return 0; }
unsigned VmaddOp::getTiedOperandIndex() { return 0; }
unsigned VmaddOp::getTiedResultIndex() { return 0; }
unsigned VusqzOp::getTiedOperandIndex() { return 0; }
unsigned VusqzOp::getTiedResultIndex() { return 0; }
unsigned VmulaOp::getTiedOperandIndex() { return 0; }
unsigned VmulaOp::getTiedResultIndex() { return 0; }
unsigned VaxpyOp::getTiedOperandIndex() { return 1; }
unsigned VaxpyOp::getTiedResultIndex() { return 0; }

static llvm::cl::opt<bool> disableVPTOAlignChainVerification(
"vpto-disable-align-chain-verification",
llvm::cl::desc("Disable !pto.align linear-chain verifier checks"),
Expand Down Expand Up @@ -7073,6 +7086,41 @@ LogicalResult VbitcastOp::verify() {
return success();
}

LogicalResult VmovOp::verify() {
bool invalidInput =
failed(verifyVRegTypeLike(*this, getInput().getType(), "input type"));
bool invalidResult =
failed(verifyVRegTypeLike(*this, getResult().getType(), "result type"));
if (invalidInput || invalidResult) {
return failure();
}
Type inputType = getInput().getType();
Type resultType = getResult().getType();
if (inputType != resultType) {
return emitOpError(
"requires input and result to have identical vector types");
}

Type elementType = cast<VRegType>(inputType).getElementType();
bool isSupportedFloat =
elementType.isF16() || elementType.isBF16() || elementType.isF32();
if (isSupportedFloat) {
return success();
}
auto integerType = dyn_cast<IntegerType>(elementType);
if (!integerType) {
return emitOpError("requires f16/bf16/f32 or integer vector element type");
}
unsigned width = integerType.getWidth();
if (width == mlir::pto::kValue8 || width == 16 ||
width == mlir::pto::kValue32 ||
(width == 64 && !integerType.isUnsigned())) {
return success();
}
return emitOpError("requires 8/16/32-bit integer or non-unsigned 64-bit "
"integer vector element type");
}

LogicalResult PdintlvB8Op::verify() {
if (failed(verifyMaskTypeWithGranularityLike(*this, getLhs().getType(),
"lhs type", "b8")) ||
Expand Down
42 changes: 42 additions & 0 deletions lib/PTO/IR/VPTOPhysicalRegister.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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.

//===- VPTOPhysicalRegister.cpp - VPTO physical register views -----------===//

#include "PTO/IR/VPTOPhysicalRegister.h"

#include "PTO/IR/PTO.h"

#include "llvm/ADT/SmallPtrSet.h"

using namespace mlir;
using namespace mlir::pto;

bool mlir::pto::isPhysicalRegisterView(Operation *op) {
return isa_and_nonnull<VbitcastOp, PbitcastOp>(op);
}

Value mlir::pto::getPhysicalRegisterViewRoot(Value value) {
llvm::SmallPtrSet<Operation *, 8> visited;
while (auto result = dyn_cast<OpResult>(value)) {
Operation *owner = result.getOwner();
if (!visited.insert(owner).second) {
break;
}
if (auto view = dyn_cast<VbitcastOp>(owner)) {
value = view.getInput();
continue;
}
if (auto view = dyn_cast<PbitcastOp>(owner)) {
value = view.getInput();
continue;
}
break;
}
return value;
}
2 changes: 1 addition & 1 deletion lib/PTO/IR/VPTOScheduling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ static void setStaticAccessRange(Operation *op, VPTOMemoryAccess &access) {
/// Pure: vector-memory barriers and register-state effects must remain visible
/// to the scheduler and to general IR transformations.
static bool hasKnownNoOrdinaryMemoryAccess(Operation *op) {
return isa<MemBarOp, SprclrOp, GetCtrlOp, SetCtrlOp>(op);
return isa<MemBarOp, SprclrOp, GetCtrlOp, SetCtrlOp, VmovOp>(op);
}

static void collectMemoryAccesses(Operation *op,
Expand Down
1 change: 1 addition & 0 deletions lib/PTO/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ add_mlir_dialect_library(PTOTransforms
VPTOCombineReductions.cpp
VPTOOptimizeVcvt.cpp
VPTOMaskSimplify.cpp
VPTOMaterializeTiedOperandCopies.cpp
VPTOExpandWrapperOps.cpp
VPTOSoftPostUpdate.cpp
PTOPrintAddressAnalysis.cpp
Expand Down
Loading
Loading