Skip to content

Commit a64d713

Browse files
authored
Implement ValueBoundsOpInterface on HAL ID/count ops, util.assume.int (iree-org#19676)
Add a model of ValueBoundsOpInterface (the one used for reasoning about affine maps and loops) to the HAL ID ops and util.assume.int to improve both loop invariant code motion and, in the future, single-iteration loop removal.
1 parent db129e5 commit a64d713

File tree

7 files changed

+126
-0
lines changed

7 files changed

+126
-0
lines changed

compiler/src/iree/compiler/Codegen/Interfaces/Interfaces.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ void registerCodegenInterfaces(DialectRegistry &registry) {
6464
affine::registerValueBoundsOpInterfaceExternalModels(registry);
6565
arith::registerValueBoundsOpInterfaceExternalModels(registry);
6666
bufferization::registerTransformDialectExtension(registry);
67+
gpu::registerValueBoundsOpInterfaceExternalModels(registry);
6768
gpu::registerTransformDialectExtension(registry);
6869
gpu::registerValueBoundsOpInterfaceExternalModels(registry);
6970
linalg::registerTransformDialectExtension(registry);

compiler/src/iree/compiler/ExternalInterfaces/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ iree_compiler_cc_library(
1616
name = "ExternalModels",
1717
srcs = [
1818
"FlowExternalModels.cpp",
19+
"HALExternalModels.cpp",
1920
"Interfaces.cpp",
2021
"LinalgExtExternalModels.cpp",
2122
"StreamExternalModels.cpp",
2223
"UtilExternalModels.cpp",
2324
],
2425
hdrs = [
2526
"FlowExternalModels.h",
27+
"HALExternalModels.h",
2628
"Interfaces.h",
2729
"LinalgExtExternalModels.h",
2830
"StreamExternalModels.h",

compiler/src/iree/compiler/ExternalInterfaces/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ iree_cc_library(
1515
ExternalModels
1616
HDRS
1717
"FlowExternalModels.h"
18+
"HALExternalModels.h"
1819
"Interfaces.h"
1920
"LinalgExtExternalModels.h"
2021
"StreamExternalModels.h"
2122
"UtilExternalModels.h"
2223
SRCS
2324
"FlowExternalModels.cpp"
25+
"HALExternalModels.cpp"
2426
"Interfaces.cpp"
2527
"LinalgExtExternalModels.cpp"
2628
"StreamExternalModels.cpp"
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025 The IREE Authors
2+
//
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
7+
#include "iree/compiler/ExternalInterfaces/HALExternalModels.h"
8+
9+
#include "iree/compiler/Dialect/HAL/IR/HALDialect.h"
10+
#include "iree/compiler/Dialect/HAL/IR/HALOps.h"
11+
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
12+
13+
namespace mlir::iree_compiler {
14+
15+
namespace {
16+
17+
//===----------------------------------------------------------------------===//
18+
// ValueBoundsOpInterface
19+
//===----------------------------------------------------------------------===//
20+
21+
template <typename IDOp>
22+
struct IDOpValueBoundsInterface : public ValueBoundsOpInterface::ExternalModel<
23+
IDOpValueBoundsInterface<IDOp>, IDOp> {
24+
void populateBoundsForIndexValue(Operation *op, Value value,
25+
ValueBoundsConstraintSet &cstr) const {
26+
auto boundOp = cast<IDOp>(op);
27+
assert(value == boundOp.getResult() && "value must be op result");
28+
cstr.bound(value) >= 0;
29+
if (boundOp.getUpperBound()) {
30+
cstr.bound(value) < boundOp.getUpperBound()->getSExtValue();
31+
}
32+
}
33+
};
34+
35+
template <typename CountOp>
36+
struct CountOpValueBoundsInterface
37+
: public ValueBoundsOpInterface::ExternalModel<
38+
CountOpValueBoundsInterface<CountOp>, CountOp> {
39+
void populateBoundsForIndexValue(Operation *op, Value value,
40+
ValueBoundsConstraintSet &cstr) const {
41+
auto boundOp = cast<CountOp>(op);
42+
assert(value == boundOp.getResult() && "value must be op result");
43+
cstr.bound(value) >= 1;
44+
if (boundOp.getUpperBound()) {
45+
cstr.bound(value) <= boundOp.getUpperBound()->getSExtValue();
46+
}
47+
}
48+
};
49+
50+
} // namespace
51+
52+
void registerHALExternalModels(DialectRegistry &registry) {
53+
registry.addExtension(+[](MLIRContext *context,
54+
IREE::HAL::HALDialect *dialect) {
55+
IREE::HAL::InterfaceWorkgroupIDOp::attachInterface<
56+
IDOpValueBoundsInterface<IREE::HAL::InterfaceWorkgroupIDOp>>(*context);
57+
58+
IREE::HAL::InterfaceWorkgroupSizeOp::attachInterface<
59+
CountOpValueBoundsInterface<IREE::HAL::InterfaceWorkgroupSizeOp>>(
60+
*context);
61+
IREE::HAL::InterfaceWorkgroupCountOp::attachInterface<
62+
CountOpValueBoundsInterface<IREE::HAL::InterfaceWorkgroupCountOp>>(
63+
*context);
64+
});
65+
}
66+
} // namespace mlir::iree_compiler
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 The IREE Authors
2+
//
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
7+
#ifndef IREE_COMPILER_EXTERNALINTERFACES_HALEXTERNALMODELS_H_
8+
#define IREE_COMPILER_EXTERNALINTERFACES_HALEXTERNALMODELS_H_
9+
10+
namespace mlir {
11+
class DialectRegistry;
12+
} // namespace mlir
13+
14+
namespace mlir::iree_compiler {
15+
16+
void registerHALExternalModels(DialectRegistry &registry);
17+
18+
} // namespace mlir::iree_compiler
19+
20+
#endif // IREE_COMPILER_EXTERNALINTERFACES_HALEXTERNALMODELS_H_

compiler/src/iree/compiler/ExternalInterfaces/Interfaces.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "iree/compiler/ExternalInterfaces/Interfaces.h"
88

99
#include "iree/compiler/ExternalInterfaces/FlowExternalModels.h"
10+
#include "iree/compiler/ExternalInterfaces/HALExternalModels.h"
1011
#include "iree/compiler/ExternalInterfaces/LinalgExtExternalModels.h"
1112
#include "iree/compiler/ExternalInterfaces/StreamExternalModels.h"
1213
#include "iree/compiler/ExternalInterfaces/UtilExternalModels.h"
@@ -15,6 +16,7 @@ namespace mlir::iree_compiler {
1516

1617
void registerExternalInterfaces(DialectRegistry &registry) {
1718
registerFlowExternalModels(registry);
19+
registerHALExternalModels(registry);
1820
registerLinalgExtExternalModels(registry);
1921
registerStreamExternalModels(registry);
2022
registerUtilExternalModels(registry);

compiler/src/iree/compiler/ExternalInterfaces/UtilExternalModels.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@
1212
#include "iree/compiler/Dialect/Encoding/IR/EncodingOps.h"
1313
#include "iree/compiler/Dialect/LinalgExt/IR/LinalgExtDialect.h"
1414
#include "iree/compiler/Dialect/LinalgExt/IR/LinalgExtOps.h"
15+
#include "iree/compiler/Dialect/Util/IR/UtilDialect.h"
16+
#include "iree/compiler/Dialect/Util/IR/UtilOps.h"
1517
#include "iree/compiler/Dialect/Util/IR/UtilTypes.h"
1618
#include "mlir/Dialect/Arith/IR/Arith.h"
1719
#include "mlir/Dialect/Linalg/IR/Linalg.h"
1820
#include "mlir/Dialect/MLProgram/IR/MLProgram.h"
1921
#include "mlir/Dialect/Tensor/IR/Tensor.h"
2022
#include "mlir/IR/Matchers.h"
23+
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
2124

2225
namespace mlir::iree_compiler {
2326

@@ -104,6 +107,31 @@ struct ArithDivUIInferIntDivisibilityOpInterface
104107
}
105108
};
106109

110+
//===----------------------------------------------------------------------===//
111+
// ValueBoundsOpInterface
112+
//===----------------------------------------------------------------------===//
113+
114+
/// For some reason, this interface has to be done as an external model.
115+
struct UtilAssumeIntValueBoundsOpInterface
116+
: public ValueBoundsOpInterface::ExternalModel<
117+
UtilAssumeIntValueBoundsOpInterface, IREE::Util::AssumeIntOp> {
118+
void populateBoundsForIndexValue(Operation *op, Value value,
119+
ValueBoundsConstraintSet &cstr) const {
120+
auto assumeOp = cast<IREE::Util::AssumeIntOp>(op);
121+
auto result = cast<OpResult>(value);
122+
assert(result.getOwner() == op && "value is a result of this index op");
123+
auto [min, max] =
124+
assumeOp.getUnionedUnsignedRange(result.getResultNumber());
125+
126+
if (min) {
127+
cstr.bound(result) >= *min;
128+
}
129+
if (max) {
130+
cstr.bound(result) <= *max;
131+
}
132+
}
133+
};
134+
107135
//===----------------------------------------------------------------------===//
108136
// GlobalOpInterface
109137
//===----------------------------------------------------------------------===//
@@ -489,6 +517,11 @@ void registerUtilExternalModels(DialectRegistry &registry) {
489517
tensor::PadOp, tensor::PackOp,
490518
tensor::UnPackOp>::registerOpInterface(context);
491519
});
520+
registry.addExtension(
521+
+[](MLIRContext *context, IREE::Util::UtilDialect *dialect) {
522+
IREE::Util::AssumeIntOp::attachInterface<
523+
UtilAssumeIntValueBoundsOpInterface>(*context);
524+
});
492525
}
493526

494527
} // namespace mlir::iree_compiler

0 commit comments

Comments
 (0)