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
1 change: 1 addition & 0 deletions include/PTO/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ std::unique_ptr<Pass> createVMILayoutFoldPass();
std::unique_ptr<Pass> createVMILayoutRematerializePass();
std::unique_ptr<Pass> createVMILayoutSinkMaterializationPass();
std::unique_ptr<Pass> createVMILegalizeArithSelectPass();
std::unique_ptr<Pass> createVMIPredicateFoldPass();
std::unique_ptr<Pass> createVMILowerUnifiedToLegacyPass();
std::unique_ptr<Pass> createVMINormalizeSignlessIntToUnsignedPass();
std::unique_ptr<Pass> createVMIToVPTOPass();
Expand Down
22 changes: 22 additions & 0 deletions include/PTO/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,28 @@ def VMINormalizeSignlessIntToUnsigned :
let dependentDialects = ["pto::PTODialect"];
}

def VMIPredicateFold : Pass<"vmi-predicate-fold", "ModuleOp"> {
let summary = "Fold statically proven VMI vcmp/vsel predicates (pad DCE)";
let description = [{
Constant-proves lane ranges for `vci` / `vadds(vci(0), C)` / `vbrc(C)`
(and simple affine `iv*stride+C` bases with known `scf.for` bounds), then:

* folds `vcmp`/`vcmps` whose result is all-true or all-false
* rewrites `vsel(all_true, t, f) → t` and `vsel(all_false, t, f) → f`
* rewrites `vsel(m, x, x) → x`
* DCEs unused compare / broadcast defs

Enables frontends to always emit expert-pad `vcmp_lt`+`vsel` and rely on
the compiler when `num_experts` covers the index span at compile time.
}];
let constructor = "mlir::pto::createVMIPredicateFoldPass()";
let dependentDialects = [
"mlir::pto::PTODialect",
"mlir::arith::ArithDialect",
"mlir::scf::SCFDialect"
];
}

def VMILowerUnifiedToLegacy : Pass<"vmi-lower-unified-to-legacy", "ModuleOp"> {
let summary = "Lower unified VMI ops to legacy equivalents before layout assignment";
let description = [{
Expand Down
36 changes: 36 additions & 0 deletions include/PTO/Transforms/VMIMaskUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.

//===- VMIMaskUtils.h - Shared VMI predicate / seed helpers -----*- C++ -*-===//
//
// Helpers shared by VMILowerUnifiedToLegacy and VMIPredicateFold for proving
// that a mask SSA value is statically all-active or all-inactive.
//
//===----------------------------------------------------------------------===//

#ifndef PTO_TRANSFORMS_VMIMASKUTILS_H
#define PTO_TRANSFORMS_VMIMASKUTILS_H

#include "mlir/IR/Value.h"

namespace mlir {
namespace pto {

/// Returns true if `seed` is provably an all-active mask (every lane active),
/// so `mask_and(x, seed)` is the identity. Covers a `pset` and a
/// `create_mask` whose active_lanes is a constant >= the mask lane count.
bool isAllActiveSeed(Value seed);

/// Returns true if `seed` is provably an all-inactive mask (every lane
/// inactive). Covers `create_mask(0)`.
bool isAllInactiveSeed(Value seed);

} // namespace pto
} // namespace mlir

#endif // PTO_TRANSFORMS_VMIMASKUTILS_H
2 changes: 2 additions & 0 deletions lib/PTO/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ add_mlir_dialect_library(PTOTransforms
VMIControlFlowSupport.cpp
VMILegalizeArithSelect.cpp
VMIMaskGranularityAssignment.cpp
VMIMaskUtils.cpp
VMIPredicateFold.cpp
VMILowerUnifiedToLegacy.cpp
VMINormalizeSignlessIntToUnsigned.cpp
VMILayoutAssignment.cpp
Expand Down
20 changes: 1 addition & 19 deletions lib/PTO/Transforms/VMILowerUnifiedToLegacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#include "PTO/IR/PTO.h"
#include "PTO/IR/PTOTypeUtils.h"
#include "PTO/Transforms/Passes.h"
#include "PTO/Transforms/VMIMaskUtils.h"

#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/IR/BuiltinOps.h"
Expand Down Expand Up @@ -304,25 +305,6 @@ lowerMaskedUnary(UnifiedOp op, OpBuilder &builder,
// Category C1 helpers: vcmp / vcmps
//===----------------------------------------------------------------------===//

/// Returns true if `seed` is provably an all-active mask (every lane active),
/// so `mask_and(x, seed)` is the identity and the AND can be skipped. Covers a
/// `pset` (all lanes active by definition) and a `create_mask` whose
/// active_lanes is a constant >= the mask lane count.
static bool isAllActiveSeed(Value seed) {
Operation *def = seed.getDefiningOp();
if (!def)
return false;
if (isa<VMIPsetOp>(def))
return true;
if (auto cm = dyn_cast<VMICreateMaskOp>(def)) {
auto maskTy = cast<VMIMaskType>(cm.getResult().getType());
if (auto cst = cm.getActiveLanes().getDefiningOp<arith::ConstantOp>())
if (auto ia = dyn_cast<IntegerAttr>(cst.getValue()))
return ia.getInt() >= maskTy.getElementCount();
}
return false;
}

/// Prepare a direct reduction result for a unit-stride group store.
///
/// Explicit grouped reductions already produce one scalar per group. A full
Expand Down
46 changes: 46 additions & 0 deletions lib/PTO/Transforms/VMIMaskUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.

//===- VMIMaskUtils.cpp - Shared VMI predicate / seed helpers -------------===//

#include "PTO/Transforms/VMIMaskUtils.h"

#include "PTO/IR/PTO.h"

#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/IR/BuiltinAttributes.h"

using namespace mlir;
using namespace mlir::pto;

bool mlir::pto::isAllActiveSeed(Value seed) {
Operation *def = seed.getDefiningOp();
if (!def)
return false;
if (isa<VMIPsetOp>(def))
return true;
if (auto cm = dyn_cast<VMICreateMaskOp>(def)) {
auto maskTy = cast<VMIMaskType>(cm.getResult().getType());
if (auto cst = cm.getActiveLanes().getDefiningOp<arith::ConstantOp>())
if (auto ia = dyn_cast<IntegerAttr>(cst.getValue()))
return ia.getInt() >= maskTy.getElementCount();
}
return false;
}

bool mlir::pto::isAllInactiveSeed(Value seed) {
Operation *def = seed.getDefiningOp();
if (!def)
return false;
if (auto cm = dyn_cast<VMICreateMaskOp>(def)) {
if (auto cst = cm.getActiveLanes().getDefiningOp<arith::ConstantOp>())
if (auto ia = dyn_cast<IntegerAttr>(cst.getValue()))
return ia.getInt() <= 0;
}
return false;
}
Loading
Loading