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
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ iree_compiler_cc_library(
"StripDebugOps.cpp",
"TestConversion.cpp",
"TestFloatRangeAnalysis.cpp",
"TestIntegerDivisibilityAnalysis.cpp",
"VerifyInitializationOrder.cpp",
"VerifyStructuredControlFlow.cpp",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ iree_cc_library(
"StripDebugOps.cpp"
"TestConversion.cpp"
"TestFloatRangeAnalysis.cpp"
"TestIntegerDivisibilityAnalysis.cpp"
"VerifyInitializationOrder.cpp"
"VerifyStructuredControlFlow.cpp"
DEPS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ createHoistIntoGlobalsPass(const ExprHoistingOptions &options);
#define GEN_PASS_DECL_STRIPDEBUGOPSPASS
#define GEN_PASS_DECL_TESTCONVERSIONPASS
#define GEN_PASS_DECL_TESTFLOATRANGEANALYSISPASS
#define GEN_PASS_DECL_TESTINTEGERDIVISIBILITYANALYSISPASS
#define GEN_PASS_DECL_VERIFYINITIALIZATIONORDERPASS
#define GEN_PASS_DECL_VERIFYSTRUCTUREDCONTROLFLOWPASS
#include "iree/compiler/Dialect/Util/Transforms/Passes.h.inc" // IWYU pragma: keep
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/iree/compiler/Dialect/Util/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,14 @@ def TestFloatRangeAnalysisPass : Pass<"iree-util-test-float-range-analysis", "">
}];
}

def TestIntegerDivisibilityAnalysisPass :
Pass<"iree-util-test-integer-divisibility-analysis", ""> {
let summary = "Tests integer divisibility analysis.";
let description = [{
Tests integer divisibility analysis by evaluating any
'iree_unregistered.test_int_divisibility' op and setting the results on an
attribute.
}];
}

#endif // IREE_DIALECT_UTIL_PASSES
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2025 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Dialect/Util/Analysis/IntegerDivisibilityAnalysis.h"
#include "iree/compiler/Dialect/Util/Transforms/Passes.h"
#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
#include "mlir/Analysis/DataFlowFramework.h"

namespace mlir::iree_compiler::IREE::Util {

#define GEN_PASS_DEF_TESTINTEGERDIVISIBILITYANALYSISPASS
#include "iree/compiler/Dialect/Util/Transforms/Passes.h.inc"

namespace {

class TestIntegerDivisibilityAnalysisPass
: public impl::TestIntegerDivisibilityAnalysisPassBase<
TestIntegerDivisibilityAnalysisPass> {
public:
void runOnOperation() override {
Operation *rootOp = getOperation();
MLIRContext *context = &getContext();

// The pass is rooted on `iree_unregistered.test_int_divisibility` ops,
// which are expected to have a single operand for which to annotate
// divisibility information.
SmallVector<std::pair<Operation *, Value>> queryOps;
rootOp->walk([&](Operation *op) {
if (op->getName().getStringRef() ==
"iree_unregistered.test_int_divisibility" &&
op->getNumOperands() == 1) {
queryOps.emplace_back(op, op->getOperand(0));
}
});

DataFlowSolver solver;
// DeadCodeAnalysis is the base analysis that allows the solver to traverse
// control flow. We include it to make the divisibility analysis more
// powerful.
solver.load<dataflow::DeadCodeAnalysis>();
solver.load<IntegerDivisibilityAnalysis>();
if (failed(solver.initializeAndRun(rootOp))) {
return signalPassFailure();
}

for (auto &[op, value] : queryOps) {
auto *lattice = solver.lookupState<IntegerDivisibilityLattice>(value);
if (!lattice || lattice->getValue().isUninitialized()) {
op->setAttr("divisibility", StringAttr::get(context, "uninitialized"));
continue;
}

// Format for the divisibility information is "udiv = X, sdiv = Y".
const auto &div = lattice->getValue().getValue();
std::string result;
llvm::raw_string_ostream os(result);
os << "udiv = " << div.udiv() << ", sdiv = " << div.sdiv();
op->setAttr("divisibility", StringAttr::get(context, os.str()));
}
}
};

} // namespace

} // namespace mlir::iree_compiler::IREE::Util
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ iree_lit_test_suite(
"strip_debug_ops.mlir",
"test_float_range_analysis.mlir",
"test_float_range_analysis_linalg.mlir",
"test_integer_divisibility_analysis.mlir",
"verify_initialization_order.mlir",
"verify_structured_control_flow.mlir",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ iree_lit_test_suite(
"strip_debug_ops.mlir"
"test_float_range_analysis.mlir"
"test_float_range_analysis_linalg.mlir"
"test_integer_divisibility_analysis.mlir"
"verify_initialization_order.mlir"
"verify_structured_control_flow.mlir"
TOOLS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// RUN: iree-opt --split-input-file --iree-util-test-integer-divisibility-analysis --allow-unregistered-dialect %s | FileCheck %s

// CHECK-LABEL: @affine_apply_mul_divisibility
util.func @affine_apply_mul_divisibility(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 8> : index
%1 = affine.apply affine_map<(d0) -> (d0 * 4)>(%0)
// CHECK: divisibility = "udiv = 32, sdiv = 32"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_mul_negative
util.func @affine_apply_mul_negative(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 8> : index
%1 = affine.apply affine_map<(d0) -> (d0 * -4)>(%0)
// CHECK: divisibility = "udiv = 32, sdiv = 32"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_add_gcd
util.func @affine_apply_add_gcd(%arg0 : index, %arg1 : index) -> index {
%0:2 = util.assume.int %arg0<udiv = 16>,
%arg1<udiv = 24> : index, index
%1 = affine.apply affine_map<(d0, d1) -> (d0 + d1)>(%0#0, %0#1)
// CHECK: divisibility = "udiv = 8, sdiv = 8"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_floordiv_exact
util.func @affine_apply_floordiv_exact(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 64> : index
%1 = affine.apply affine_map<(d0) -> (d0 floordiv 4)>(%0)
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_ceildiv_exact
util.func @affine_apply_ceildiv_exact(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 64> : index
%1 = affine.apply affine_map<(d0) -> (d0 ceildiv 4)>(%0)
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_floordiv_non_exact
util.func @affine_apply_floordiv_non_exact(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 20> : index
%1 = affine.apply affine_map<(d0) -> (d0 floordiv 3)>(%0)
// CHECK: divisibility = "udiv = 1, sdiv = 1"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_mod
util.func @affine_apply_mod(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 16> : index
%1 = affine.apply affine_map<(d0) -> (d0 mod 16)>(%0)
// CHECK: divisibility = "udiv = 1, sdiv = 1"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_composition
util.func @affine_apply_composition(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 8> : index
%1 = affine.apply affine_map<(d0) -> (d0 * 4 + 16)>(%0)
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_apply_with_symbol
util.func @affine_apply_with_symbol(%arg0 : index, %arg1 : index) -> index {
%0:2 = util.assume.int %arg0<udiv = 16>,
%arg1<udiv = 16> : index, index
%1 = affine.apply affine_map<(d0)[s0] -> (d0 + s0)>(%0#0)[%0#1]
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_min_uniform_divisibility
util.func @affine_min_uniform_divisibility(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 16> : index
%1 = affine.min affine_map<(d0) -> (d0, d0 + 64)>(%0)
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_min_different_divisibilities
util.func @affine_min_different_divisibilities(%arg0 : index, %arg1 : index) -> index {
%0:2 = util.assume.int %arg0<udiv = 16>,
%arg1<udiv = 24> : index, index
%1 = affine.min affine_map<(d0, d1) -> (d0, d1)>(%0#0, %0#1)
// CHECK: divisibility = "udiv = 8, sdiv = 8"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_max_uniform_divisibility
util.func @affine_max_uniform_divisibility(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 32> : index
%1 = affine.max affine_map<(d0) -> (d0, d0 - 64)>(%0)
// CHECK: divisibility = "udiv = 32, sdiv = 32"
%2 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
util.return %2 : index
}

// -----

// CHECK-LABEL: @affine_max_different_divisibilities
util.func @affine_max_different_divisibilities(%arg0 : index, %arg1 : index, %arg2 : index) -> index {
%0:3 = util.assume.int %arg0<udiv = 12>,
%arg1<udiv = 24>,
%arg2<udiv = 18> : index, index, index
%3 = affine.max affine_map<(d0, d1, d2) -> (d0, d1, d2)>(%0#0, %0#1, %0#2)
// CHECK: divisibility = "udiv = 6, sdiv = 6"
%4 = "iree_unregistered.test_int_divisibility"(%3) : (index) -> index
util.return %4 : index
}

// -----

// CHECK-LABEL: @affine_apply_constant
util.func @affine_apply_constant() -> index {
%0 = affine.apply affine_map<() -> (64)>()
// CHECK: divisibility = "udiv = 64, sdiv = 64"
%1 = "iree_unregistered.test_int_divisibility"(%0) : (index) -> index
util.return %1 : index
}

// -----

// CHECK-LABEL: @affine_apply_chained_operations
util.func @affine_apply_chained_operations(%arg0 : index) -> index {
%0 = util.assume.int %arg0<udiv = 4> : index
%1 = affine.apply affine_map<(d0) -> (d0 * 8)>(%0)
%2 = affine.apply affine_map<(d0) -> (d0 + 16)>(%1)
// CHECK: divisibility = "udiv = 16, sdiv = 16"
%3 = "iree_unregistered.test_int_divisibility"(%2) : (index) -> index
util.return %3 : index
}

// -----

// CHECK-LABEL: @complex_chained_affine_ops
util.func @complex_chained_affine_ops(%arg0 : index, %arg1 : index, %arg2 : index) -> index {
%0:3 = util.assume.int %arg0<udiv = 210>,
%arg1<udiv = 7>,
%arg2<udiv = 15> : index, index, index
%1 = affine.apply affine_map<(d0, d1) -> (d0 + 2 * d1)>(%0#0, %0#1)
// CHECK: divisibility = "udiv = 14, sdiv = 14"
%div_1 = "iree_unregistered.test_int_divisibility"(%1) : (index) -> index
%2 = affine.max affine_map<(d0, d1) -> (d0 floordiv 6, d1 * 3)>(%0#0, %0#2)
// CHECK: divisibility = "udiv = 5, sdiv = 5"
%div_2 = "iree_unregistered.test_int_divisibility"(%2) : (index) -> index
%3 = affine.min affine_map<(d0)[s0] -> (2 * (s0 * d0 - 14) ceildiv 7, d0 floordiv 3 * 2)>(%2)[%1]
// CHECK: divisibility = "udiv = 2, sdiv = 2"
%div_3 = "iree_unregistered.test_int_divisibility"(%3) : (index) -> index
util.return %div_3 : index
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ iree_compiler_cc_library(
"//compiler/src/iree/compiler/Dialect/TensorExt/IR",
"//compiler/src/iree/compiler/Dialect/Util/IR",
"@llvm-project//llvm:Support",
"@llvm-project//mlir:AffineDialect",
"@llvm-project//mlir:ArithDialect",
"@llvm-project//mlir:BufferizationInterfaces",
"@llvm-project//mlir:ControlFlowInterfaces",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ iree_cc_library(
"UtilExternalModels.cpp"
DEPS
LLVMSupport
MLIRAffineDialect
MLIRArithDialect
MLIRControlFlowInterfaces
MLIRGPUDialect
Expand Down
Loading
Loading