[Mlir-commits] [mlir] [mlir] Add option to cloning for different results (PR #184202)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Mar 2 10:47:33 PST 2026
https://github.com/tdegioanni-nvidia updated https://github.com/llvm/llvm-project/pull/184202
>From 6b9eba81423cac15991bd0317e869c4d258f47f2 Mon Sep 17 00:00:00 2001
From: Theo Degioanni <tdegioanni at nvidia.com>
Date: Mon, 2 Mar 2026 19:34:06 +0100
Subject: [PATCH 1/2] [mlir] Add option to cloning for different results
Co-authored-by: zero9178 <markus.boeck02 at gmail.com>
---
mlir/include/mlir/IR/Operation.h | 37 +++++++++++++++++-----
mlir/lib/IR/Operation.cpp | 31 ++++++++++++------
mlir/unittests/IR/OperationSupportTest.cpp | 16 ++++++++++
3 files changed, 67 insertions(+), 17 deletions(-)
diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h
index b2019574a820d..5e40b7b865fe1 100644
--- a/mlir/include/mlir/IR/Operation.h
+++ b/mlir/include/mlir/IR/Operation.h
@@ -140,18 +140,20 @@ class alignas(8) Operation final
/// * Whether cloning should recursively traverse into the regions of the
/// operation or not.
/// * Whether cloning should also clone the operands of the operation.
+ /// * Whether to use different result types or clone them.
class CloneOptions {
public:
/// Default constructs an option with all flags set to false. That means all
/// parts of an operation that may optionally not be cloned, are not cloned.
CloneOptions();
- /// Constructs an instance with the clone regions and clone operands flags
- /// set accordingly.
- CloneOptions(bool cloneRegions, bool cloneOperands);
+ /// Constructs an instance with the options set accordingly.
+ CloneOptions(bool cloneRegions, bool cloneOperands,
+ std::optional<SmallVector<Type>> resultTypes);
- /// Returns an instance with all flags set to true. This is the default
- /// when using the clone method and clones all parts of the operation.
+ /// Returns an instance such that all elements of the operation are cloned.
+ /// This is the default when using the clone method and clones all parts of
+ /// the operation.
static CloneOptions all();
/// Configures whether cloning should traverse into any of the regions of
@@ -172,11 +174,29 @@ class alignas(8) Operation final
/// Returns whether operands should be cloned as well.
bool shouldCloneOperands() const { return cloneOperandsFlag; }
+ /// Configures different result types to use for the cloned operation.
+ /// If an empty optional, the result types are cloned from the original
+ /// operation.
+ CloneOptions &withResultTypes(std::optional<SmallVector<Type>> resultTypes);
+
+ /// Returns true if the results are cloned from the operation.
+ bool shouldCloneResults() const { return !resultTypes.has_value(); }
+
+ /// Returns the result types that should be used for the created operation
+ /// or `defaultResultTypes` if none were set.
+ TypeRange resultTypesOr(TypeRange defaultResultTypes) const {
+ if (resultTypes)
+ return *resultTypes;
+ return defaultResultTypes;
+ }
+
private:
/// Whether regions should be cloned.
bool cloneRegionsFlag : 1;
/// Whether operands should be cloned.
bool cloneOperandsFlag : 1;
+ /// New result types to use in the cloned operation.
+ std::optional<SmallVector<Type>> resultTypes;
};
/// Create a deep copy of this operation, remapping any operands that use
@@ -185,7 +205,8 @@ class alignas(8) Operation final
/// sub-operations to the corresponding operation that is copied, and adds
/// those mappings to the map.
/// Optionally, one may configure what parts of the operation to clone using
- /// the options parameter.
+ /// the options parameter. If parts of the operation (e.g. results or regions)
+ /// are not cloned, they will not appear in the mapper.
///
/// Calling this method from multiple threads is generally safe if through the
/// process of cloning no new uses of 'Value's from outside the operation are
@@ -194,8 +215,8 @@ class alignas(8) Operation final
/// mapper, it is possible to avoid adding uses to outside operands by
/// remapping them to 'Value's owned by the caller thread.
Operation *clone(IRMapping &mapper,
- CloneOptions options = CloneOptions::all());
- Operation *clone(CloneOptions options = CloneOptions::all());
+ const CloneOptions &options = CloneOptions::all());
+ Operation *clone(const CloneOptions &options = CloneOptions::all());
/// Create a partial copy of this operation without traversing into attached
/// regions. The new operation will have the same number of regions as the
diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp
index bf8a918641dfb..46030936a3910 100644
--- a/mlir/lib/IR/Operation.cpp
+++ b/mlir/lib/IR/Operation.cpp
@@ -674,13 +674,18 @@ InFlightDiagnostic Operation::emitOpError(const Twine &message) {
//===----------------------------------------------------------------------===//
Operation::CloneOptions::CloneOptions()
- : cloneRegionsFlag(false), cloneOperandsFlag(false) {}
+ : cloneRegionsFlag(false), cloneOperandsFlag(false),
+ resultTypes(std::nullopt) {}
-Operation::CloneOptions::CloneOptions(bool cloneRegions, bool cloneOperands)
- : cloneRegionsFlag(cloneRegions), cloneOperandsFlag(cloneOperands) {}
+Operation::CloneOptions::CloneOptions(
+ bool cloneRegions, bool cloneOperands,
+ std::optional<SmallVector<Type>> resultTypes)
+ : cloneRegionsFlag(cloneRegions), cloneOperandsFlag(cloneOperands),
+ resultTypes(resultTypes) {}
Operation::CloneOptions Operation::CloneOptions::all() {
- return CloneOptions().cloneRegions().cloneOperands();
+ return CloneOptions().cloneRegions().cloneOperands().withResultTypes(
+ std::nullopt);
}
Operation::CloneOptions &Operation::CloneOptions::cloneRegions(bool enable) {
@@ -693,6 +698,12 @@ Operation::CloneOptions &Operation::CloneOptions::cloneOperands(bool enable) {
return *this;
}
+Operation::CloneOptions &Operation::CloneOptions::withResultTypes(
+ std::optional<SmallVector<Type>> resultTypes) {
+ this->resultTypes = std::move(resultTypes);
+ return *this;
+}
+
/// Create a deep copy of this operation but keep the operation regions empty.
/// Operands are remapped using `mapper` (if present), and `mapper` is updated
/// to contain the results. The `mapResults` flag specifies whether the results
@@ -711,7 +722,7 @@ Operation *Operation::cloneWithoutRegions() {
/// them alone if no entry is present). Replaces references to cloned
/// sub-operations to the corresponding operation that is copied, and adds
/// those mappings to the map.
-Operation *Operation::clone(IRMapping &mapper, CloneOptions options) {
+Operation *Operation::clone(IRMapping &mapper, const CloneOptions &options) {
SmallVector<Value, 8> operands;
SmallVector<Block *, 2> successors;
@@ -728,7 +739,8 @@ Operation *Operation::clone(IRMapping &mapper, CloneOptions options) {
successors.push_back(mapper.lookupOrDefault(successor));
// Create the new operation.
- auto *newOp = create(getLoc(), getName(), getResultTypes(), operands, attrs,
+ auto *newOp = create(getLoc(), getName(),
+ options.resultTypesOr(getResultTypes()), operands, attrs,
getPropertiesStorage(), successors, getNumRegions());
mapper.map(this, newOp);
@@ -739,13 +751,14 @@ Operation *Operation::clone(IRMapping &mapper, CloneOptions options) {
}
// Remember the mapping of any results.
- for (unsigned i = 0, e = getNumResults(); i != e; ++i)
- mapper.map(getResult(i), newOp->getResult(i));
+ if (options.shouldCloneResults())
+ for (unsigned i = 0, e = getNumResults(); i != e; ++i)
+ mapper.map(getResult(i), newOp->getResult(i));
return newOp;
}
-Operation *Operation::clone(CloneOptions options) {
+Operation *Operation::clone(const CloneOptions &options) {
IRMapping mapper;
return clone(mapper, options);
}
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index 9f3e7ed34a27d..73babc4c4fbb7 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -356,4 +356,20 @@ TEST(OperationEquivalenceTest, HashWorksWithFlags) {
opWithProperty2->destroy();
}
+TEST(OperationCloneTest, CloneWithDifferentResults) {
+ MLIRContext context;
+ Builder builder(&context);
+
+ Operation *useOp = createOp(&context, std::nullopt, builder.getI32Type());
+ IRMapping map;
+ Operation *cloneOp = useOp->clone(
+ map, Operation::CloneOptions::all().withResultTypes(
+ SmallVector<Type>{builder.getI32Type(), builder.getI16Type()}));
+
+ ASSERT_EQ(cloneOp->getNumResults(), 2u);
+ EXPECT_EQ(cloneOp->getResult(0).getType(), builder.getI32Type());
+ EXPECT_EQ(cloneOp->getResult(1).getType(), builder.getI16Type());
+ EXPECT_FALSE(map.contains(useOp->getResult(0)));
+}
+
} // namespace
>From 84164758fb50cf000f668a83a99eda1528acbf44 Mon Sep 17 00:00:00 2001
From: Theo Degioanni <tdegioanni at nvidia.com>
Date: Mon, 2 Mar 2026 19:43:46 +0100
Subject: [PATCH 2/2] update test
---
mlir/unittests/IR/OperationSupportTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index 73babc4c4fbb7..fc567bc4a8048 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -360,7 +360,7 @@ TEST(OperationCloneTest, CloneWithDifferentResults) {
MLIRContext context;
Builder builder(&context);
- Operation *useOp = createOp(&context, std::nullopt, builder.getI32Type());
+ Operation *useOp = createOp(&context, {}, builder.getI32Type());
IRMapping map;
Operation *cloneOp = useOp->clone(
map, Operation::CloneOptions::all().withResultTypes(
More information about the Mlir-commits
mailing list