[llvm-branch-commits] [mlir] [mlir] Static assert on a single-result fold on an op without `OneResult` (PR #228746)
Victor Perez via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Oct 3 10:02:02 PDT 2026
https://github.com/victor-eds created https://github.com/llvm/llvm-project/pull/228746
`getFoldHookFn` selects the single-result `OpFoldResult fold(...)` form only if the op has the OneResult trait. On an op with a single result, but without this trait, `getFoldHookFn` ignores the fold method without a diagnostic. At the moment, only a hand-written declaration can cause the problem via a `fold` in `extraClassDeclaration`, or an op class written in C++.
Add a `static_assert` that rejects a single-result fold on an op without the OneResult trait.
No new test is added, as this would lead to a compile error. This is intended to prevent operations like this one, which are allowed, but can lead to unexpected behaviour, as canonicalize will never fold the op:
```console
$ mlir-opt two_results_single_fold.mlir -canonicalize
module {
func.func @two_results_single_fold(%arg0: i32) -> (i32, i32) {
%0:2 = "test.op_two_results_single_fold"(%arg0) : (i32) -> (i32, i32)
return %0#0, %0#1 : i32, i32
}
}
```
With this patch, such an op would not compile:
```console
mlir/include/mlir/IR/OpDefinition.h:1905:19: error: static assertion failed due to requirement 'hasOneResult || !hasSingleResultFold': a single-result `OpFoldResult fold(...)` requires the OneResult trait; ops with zero, several, or variadic results must use `LogicalResult fold(FoldAdaptor, SmallVectorImpl<OpFoldResult> &)`
```
Downstream impact:
- An op without the OneResult trait that defines a single-result `fold` no longer compiles. It must use the multi-result form `LogicalResult fold(FoldAdaptor, SmallVectorImpl<OpFoldResult> &)`.
>From 6c1b819bd009d339eea30af95057db8cc081cfae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20P=C3=A9rez=20Carrasco?=
<victor.pc.upm at gmail.com>
Date: Fri, 2 Oct 2026 14:24:44 -0700
Subject: [PATCH] [mlir] Diagnose a single-result fold on an op without
OneResult
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
`getFoldHookFn` selects the single-result `OpFoldResult fold(...)` form
only if the op has the OneResult trait. On an op without this trait,
the dispatch ignores such a fold without a diagnostic. ODS declares this
form only for an op with exactly one fixed result. So only a
hand-written declaration can cause the problem: a `fold` in
`extraClassDeclaration`, or an op class written in C++. No in-tree op
does this.
Add a `static_assert` that rejects a single-result fold on an op
without the OneResult trait.
No lit test can check a compile error. A scratch test op shows the bug:
it has two results and a single-result fold that prints a line and
returns its operand. Without this patch, the op compiles, and
canonicalize never calls the fold:
$ mlir-opt two_results_single_fold.mlir -canonicalize
module {
func.func @two_results_single_fold(%arg0: i32) -> (i32, i32) {
%0:2 = "test.op_two_results_single_fold"(%arg0) : (i32) -> (i32, i32)
return %0#0, %0#1 : i32, i32
}
}
With this patch, the test op does not compile:
mlir/include/mlir/IR/OpDefinition.h:1905:19: error: static assertion
failed due to requirement 'hasOneResult || !hasSingleResultFold': a
single-result `OpFoldResult fold(...)` requires the OneResult trait;
ops with zero, several, or variadic results must use `LogicalResult
fold(FoldAdaptor, SmallVectorImpl<OpFoldResult> &)`
Downstream impact:
- An op without the OneResult trait that defines a single-result `fold`
no longer compiles. It must use the multi-result form
`LogicalResult fold(FoldAdaptor, SmallVectorImpl<OpFoldResult> &)`.
Signed-off-by: Víctor Pérez Carrasco <victor.pc.upm at gmail.com>
---
mlir/include/mlir/IR/OpDefinition.h | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h
index cb35ba7c8eaa2..783cd1359e970 100644
--- a/mlir/include/mlir/IR/OpDefinition.h
+++ b/mlir/include/mlir/IR/OpDefinition.h
@@ -1897,11 +1897,18 @@ class Op : public OpState, public Traits<ConcreteType>... {
/// Return the internal implementations of each of the OperationName hooks.
static constexpr FoldHookFn getFoldHookFn() {
+ constexpr bool hasOneResult = hasTrait<OpTrait::OneResult>();
+ constexpr bool hasSingleResultFold =
+ has_single_result_fold_v<ConcreteType> ||
+ has_fold_adaptor_single_result_v<ConcreteType>;
+ // Without this check, the dispatch below silently skips such a `fold`.
+ static_assert(hasOneResult || !hasSingleResultFold,
+ "a single-result `OpFoldResult fold(...)` requires the "
+ "OneResult trait; ops with zero, several, or variadic "
+ "results must use `LogicalResult fold(FoldAdaptor, "
+ "SmallVectorImpl<OpFoldResult> &)`");
// If the operation is single result and defines a `fold` method.
- if constexpr (llvm::is_one_of<OpTrait::OneResult<ConcreteType>,
- Traits<ConcreteType>...>::value &&
- (has_single_result_fold_v<ConcreteType> ||
- has_fold_adaptor_single_result_v<ConcreteType>))
+ if constexpr (hasOneResult && hasSingleResultFold)
return [](Operation *op, ArrayRef<Attribute> operands,
SmallVectorImpl<OpFoldResult> &results) {
return foldSingleResultHook<ConcreteType>(op, operands, results);
More information about the llvm-branch-commits
mailing list