74 Commits

Author SHA1 Message Date
Mehdi Amini
9cae8ec551 [MLIR] Apply clang-tidy fixes for bugprone-argument-comment in SparseTensorDescriptor.cpp (NFC) 2025-12-17 05:30:01 -08:00
Govind Malasani
6f5c8fe1c1
[MLIR][SparseTensor] Dense Outer Loop Ordering Strategy (#160168)
This PR builds upon the infrastructure set up for Sparse Tensor Loop
Ordering Heuristics (#154656) by adding a preference to have dense loops
outer and sparse loops inner.

As always I'd love to get feedback and know if there's any other
direction to go with this work that might be better.
2025-11-17 09:01:44 -08:00
Kazu Hirata
ff8ed4d80a
[mlir] Use llvm::copy (NFC) (#168213)
Identified with llvm-use-ranges.
2025-11-15 10:54:01 -08:00
Jordan Rupprecht
34c58c8b7c
[mlir][sparse] Include sparse emit strategy in wrapping iterator (#165611)
When we create a `SparseIterator`, we sometimes wrap it in a
`FilterIterator`, which delegates _some_ calls to the underlying
`SparseIterator`.

After construction, e.g. in `makeNonEmptySubSectIterator()`, we call
`setSparseEmitStrategy()`. This sets the strategy only in one of the
filters -- if we call `setSparseEmitStrategy()` immediately after
creating the `SparseIterator`, then the wrapped `SparseIterator` will
have the right strategy, and the `FilterIterator` strategy will be
unintialized; if we call `setSparseEmitStrategy()` after wrapping the
iterator in `FilterIterator`, then the opposite happens.

If we make `setSparseEmitStrategy()` a virtual method so that it's
included in the `FilterIterator` pattern, and then do all reads of
`emitStrategy` via a virtual method as well, it's pretty simple to
ensure that the value of `strategy` is being set consistently and
correctly.

Without this, the UB of strategy being uninitialized manifests as a
sporadic test failure in
mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_strided_conv_2d_nhwc_hwcf.mlir,
when run downstream with the right flags (e.g. asan + assertions off).
The test sometimes fails with `ne_sub<trivial<dense[0,1]>>.begin' op
created with unregistered dialect`. It can also be directly observed w/
msan that this uninitialized read is the cause of that issue, but msan
causes other problems w/ this test.
2025-10-29 15:40:05 -05:00
Slava Gurevich
2fc4d0ecd1
[MLIR] Fix use-after-move in debug logging (#165208)
1. In `Transforms.cpp` the debug macro is accessing a SmallVector
variable that has been moved-from and reset. Fixed by reordering code
for the move-from to happen last.

2. `IterationGraphSorter` Refine the previous use-after-move fix for
style/readability by renaming the private constructor args to resolve
naming ambiguity with the class members.

Testing: `ninja check-mlir`
2025-10-28 17:01:01 -07:00
Slava Gurevich
5dcf82d3da
[MLIR] Fix use-after-move for DEBUG builds, and broken assert logic. (#164763)
These issues affect only Debug builds, and Release builds with asserts
enabled.

1. In `SparseTensor.h` a variable is moved-from within an assert,
introducing a side effect that alters its subsequent use, and causes
divergence between Debug and Release builds (with asserts disabled).

2. In `IterationGraphSorter.cpp`, the class constructor arguments are
moved-from to initialize class member variables via the initializer
list. Because both the arguments and class members are identically
named, there's a naming collision where the arguments shadow their
identically-named member variables counterparts inside the constructor
body. In the original code, unqualified names inside the asserts,
referred to the constructor arguments. This is wrong, because these have
already been moved-from. It's not just a UB, but is broken. These
SmallVector types when moved-from are reset i.e. the size resets to 0.
This actually renders the affected asserts ineffective, since the
comparisons operate on two hollowed-out objects and always succeed. This
name ambiguity is fixed by using 'this->' to correctly refer to the
initialized member variables carrying the relevant state.

3. While the fix 2 above made the asserts act as intended, it also
unexpectedly broke one mlir test: `llvm-lit -v
mlir/test/Dialect/SparseTensor/sparse_scalars.mlir` This required fixing
the assert logic itself, which likely has never worked and went
unnoticed all this time due to the bug 2. Specifically, in the failing
test that uses `mlir/test/Dialect/SparseTensor/sparse_scalars.mlir` the
'%argq' of 'ins' is defined as 'f32' scalar type, but the original code
inside the assert had no support for scalar types as written, and was
breaking the test.

Testing:
```
ninja check-mlir
llvm-lit -v mlir/test/Dialect/SparseTensor/sparse_scalars.mlir
```
2025-10-25 20:35:34 -07:00
Kazu Hirata
6870f68978
[mlir] Replace LLVM_ATTRIBUTE_UNUSED with [[maybe_unused]] (NFC) (#163703)
This patch replaces LLVM_ATTRIBUTE_UNUSED with [[maybe_unused]],
introduced as part of C++17.
2025-10-16 06:52:36 -07:00
Govind Malasani
95e0ae9fa7
[MLIR][SparseTensor] Loop ordering strategy infrastructure (flag) (#154656)
As discussed before, this PR adds the basic infrastructure/boiler plate
for loop ordering strategies to be implemented.

If this looks ok, I wanted to also mention some of the heuristics that I
would implement next, if they sound reasonable to you guys:
- Parallel first : prioritize parallel loops over reduction loops
- Dense outer : prioritize the most dense loops first
- Sparse outer : the opposite, potentially useful in some cases?

There is another that I am considering, stride/memory aware, which would
prioritize loops with better stride patterns (like sequential or
linear). Not sure how well this carries over to Sparse Tensor though.
Are there any ideas/heuristics that I should definitely try to
implement?

As we discussed, I will try to incrementally add heuristics. Sorry for
the delay on my end, and thank you so much for the feedback!

---------

Co-authored-by: Aart Bik <ajcbik@google.com>
2025-10-06 17:29:48 +00:00
Mehdi Amini
600e97dfea [MLIR] Apply clang-tidy fixes for modernize-use-emplace in LoopEmitter.cpp (NFC) 2025-09-29 01:10:16 -07:00
Maksim Levental
972ac59c9a
[mlir][NFC] update mlir/Dialect create APIs (21/n) (#149928)
See https://github.com/llvm/llvm-project/pull/147168 for more info.
2025-07-22 08:15:27 -04:00
Kazu Hirata
433a5a7c20
[mlir] Remove unused includes (NFC) (#148396) 2025-07-12 15:46:34 -07:00
Longsheng Mou
5a8e60e724
[mlir] Use llvm::fill instead of std::fill(NFC) (#146889) 2025-07-07 09:12:38 +08:00
Kazu Hirata
abc2c3a538
[mlir] Use llvm::is_contained instead of llvm::all_of (NFC) (#145845)
llvm::is_contained is shorter than llvm::all_of plus a lambda.
2025-06-26 08:41:26 -07:00
Andrei Golubev
ee070d0816
[mlir][bufferization] Support custom types (1/N) (#142986)
Following the addition of TensorLike and BufferLike type interfaces (see
00eaff3e9c897c263a879416d0f151d7ca7eeaff), introduce minimal changes
required to bufferize a custom tensor operation into a custom buffer
operation.

To achieve this, new interface methods are added to TensorLike type
interface that abstract away the differences between existing (tensor ->
memref) and custom conversions.

The scope of the changes is intentionally limited (for example,
BufferizableOpInterface is untouched) in order to first understand the
basics and reach consensus design-wise.

---
Notable changes:
* mlir::bufferization::getBufferType() returns BufferLikeType (instead
of BaseMemRefType)
* ToTensorOp / ToBufferOp operate on TensorLikeType / BufferLikeType.
Operation argument "memref" renamed to "buffer"
* ToTensorOp's tensor type inferring builder is dropped (users now need
to provide the tensor type explicitly)
2025-06-18 16:18:12 +02:00
Kazu Hirata
6464238dc0
[mlir] Use llvm::stable_sort (NFC) (#141186) 2025-05-22 22:36:32 -07:00
Matthias Springer
ef1bb2a243
[mlir][SparseTensor] Fix unused variable error (#140428) 2025-05-18 10:55:09 +09:00
Matthias Springer
3360a23e60
[mlir][SparseTensor] Fix type conversion rule (#140350)
A type conversion rule cannot make any assumptions about the number of
pre-existing types in the `results` vector.

This commit fixes a failed assertion in a SparseTensor type conversion
rule. This is only reproducible when type conversion caching is
deactivated. There's no way to do this at the moment. This commit is in
preparation of adding context-aware type conversions, which will
deactivate type caching in such cases.
2025-05-18 09:21:33 +09:00
Iris Shi
78af0f3ab8
[mlir][NFC] Use llvm::sort (#140261) 2025-05-16 23:35:13 +08:00
Andrei Golubev
8f91b108df
[mlir][bufferization][NFC] Rename to_memref to to_buffer (#137180)
As part of the work on transitioning bufferization dialect, ops, and
associated logic to operate on newly added type interfaces (see
00eaff3e9c897c263a879416d0f151d7ca7eeaff), rename the
bufferization.to_memref to highlight the generic nature of the op.

Bufferization process produces buffers while memref is a builtin type
rather than a generic term.

Preserve the current API (to_buffer still produces a memref), however,
as the new type interfaces are not used yet.
2025-05-14 11:17:09 +02:00
Max Graey
8aaac80ddd
[NFC] Use more isa and isa_and_nonnull instead dyn_cast for predicates (#137393)
Also fix some typos in comments

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
2025-05-13 22:34:42 +08:00
Kazu Hirata
921d162460
[mlir] Remove unused local variables (NFC) (#138642) 2025-05-06 07:55:50 -07:00
Kazu Hirata
356ff75e07
[mlir] Use llvm::less_first (NFC) (#136398) 2025-04-18 20:34:42 -07:00
Jakub Kuderski
0078cf79ad
[mlir] Remove deprecated cast member functions (#135556)
These have been deprecated for over two years now in favor of free
functions.

See the relevant discourse thread:

https://discourse.llvm.org/t/preferred-casting-style-going-forward/68443
and the deprecation notice: https://mlir.llvm.org/deprecation/.
2025-04-14 09:08:34 -04:00
Matthias Springer
6c867e27a7
[mlir] Use getSingleElement/hasSingleElement in various places (#131460)
This is a code cleanup. Update a few places in MLIR that should use
`hasSingleElement`/`getSingleElement`.

Note: `hasSingleElement` is faster than `.getSize() == 1` when it is
used with linked lists etc.

Depends on #131508.
2025-03-17 07:43:18 +01:00
Matthias Springer
3ace685105
[mlir][Transforms] Support 1:N mappings in ConversionValueMapping (#116524)
This commit updates the internal `ConversionValueMapping` data structure
in the dialect conversion driver to support 1:N replacements. This is
the last major commit for adding 1:N support to the dialect conversion
driver.

Since #116470, the infrastructure already supports 1:N replacements. But
the `ConversionValueMapping` still stored 1:1 value mappings. To that
end, the driver inserted temporary argument materializations (converting
N SSA values into 1 value). This is no longer the case. Argument
materializations are now entirely gone. (They will be deleted from the
type converter after some time, when we delete the old 1:N dialect
conversion driver.)

Note for LLVM integration: Replace all occurrences of
`addArgumentMaterialization` (except for 1:N dialect conversion passes)
with `addSourceMaterialization`.

---------

Co-authored-by: Markus Böck <markus.boeck02@gmail.com>
2025-01-03 16:11:56 +01:00
Kazu Hirata
129f1001c3
[Dialect] Migrate away from PointerUnion::{is,get} (NFC) (#120818)
Note that PointerUnion::{is,get} have been soft deprecated in
PointerUnion.h:

  // FIXME: Replace the uses of is(), get() and dyn_cast() with
  //        isa<T>, cast<T> and the llvm::dyn_cast<T>

I'm not touching PointerUnion::dyn_cast for now because it's a bit
complicated; we could blindly migrate it to dyn_cast_if_present, but
we should probably use dyn_cast when the operand is known to be
non-null.
2024-12-21 08:17:51 -08:00
Matthias Springer
9df63b2651
[mlir][Transforms] Add 1:N matchAndRewrite overload (#116470)
This commit adds a new `matchAndRewrite` overload to `ConversionPattern`
to support 1:N replacements. This is the first of two main PRs that
merge the 1:1 and 1:N dialect conversion drivers.

The existing `matchAndRewrite` function supports only 1:1 replacements,
as can be seen from the `ArrayRef<Value>` parameter.
```c++
LogicalResult ConversionPattern::matchAndRewrite(
    Operation *op, ArrayRef<Value> operands /*adaptor values*/,
    ConversionPatternRewriter &rewriter) const;
```

This commit adds a `matchAndRewrite` overload that is called by the
dialect conversion driver. By default, this new overload dispatches to
the original 1:1 `matchAndRewrite` implementation. Existing
`ConversionPattern`s do not need to be changed as long as there are no
1:N type conversions or value replacements.
```c++
LogicalResult ConversionPattern::matchAndRewrite(
    Operation *op, ArrayRef<ValueRange> operands /*adaptor values*/,
    ConversionPatternRewriter &rewriter) const {
  // Note: getOneToOneAdaptorOperands produces a fatal error if at least one
  // ValueRange has 0 or more than 1 value.
  return matchAndRewrite(op, getOneToOneAdaptorOperands(operands), rewriter);
}
```

The `ConversionValueMapping`, which keeps track of value replacements
and materializations, still does not support 1:N replacements. We still
rely on argument materializations to convert N replacement values back
into a single value. The `ConversionValueMapping` will be generalized to
1:N mappings in the second main PR.

Before handing the adaptor values to a `ConversionPattern`, all argument
materializations are "unpacked". The `ConversionPattern` receives N
replacement values and does not see any argument materializations. This
implementation strategy allows us to use the 1:N infrastructure/API in
`ConversionPattern`s even though some functionality is still missing in
the driver. This strategy was chosen to keep the sizes of the PRs
smaller and to make it easier for downstream users to adapt to API
changes.

This commit also updates the the "decompose call graphs" transformation
and the "sparse tensor codegen" transformation to use the new 1:N
`ConversionPattern` API.

Note for LLVM conversion: If you are using a type converter with 1:N
type conversion rules or if your patterns are performing 1:N
replacements (via `replaceOpWithMultiple` or
`applySignatureConversion`), conversion pattern applications will start
failing (fatal LLVM error) with this error message: `pattern 'name' does
not support 1:N conversion`. The name of the failing pattern is shown in
the error message. These patterns must be updated to the new 1:N
`matchAndRewrite` API.
2024-11-30 09:27:47 +09:00
Matthias Springer
204234a69c
[mlir][SparseTensor][NFC] Pass tensor type to descriptor helper (#116468)
`getDescriptorFromTensorTuple` and `getMutDescriptorFromTensorTuple`
extract the tensor type from an `unrealized_conversion_cast` op that
serves as a workaround for missing 1:N dialect conversion support.

This commit changes these functions so that they explicitly receive the
tensor type as a function argument. This is in preparation of merging
the 1:1 and 1:N conversion drivers. The conversion patterns in this file
will soon start receiving multiple SSA values (`ValueRange`) from their
adaptors (instead of a single value that is the result of
`unrealized_conversion_cast`). It will no longer be possible to take the
tensor type from the `unrealized_conversion_cast` op. The
`unrealized_conversion_cast` workaround will disappear entirely.
2024-11-19 09:27:51 +09:00
Matthias Springer
aed4356252
[mlir][Transforms] Dialect Conversion: Add replaceOpWithMultiple (#115816)
This commit adds a new function
`ConversionPatternRewriter::replaceOpWithMultiple`. This function is
similar to `replaceOp`, but it accepts multiple `ValueRange`
replacements, one per op result.

Note: This function is not an overload of `replaceOp` because of
ambiguous overload resolution that would make the API difficult to use.

This commit aligns "block signature conversions" with "op replacements":
both support 1:N replacements now. Due to incomplete 1:N support in the
dialect conversion driver, an argument materialization is inserted when
an SSA value is replaced with multiple values; same as block signature
conversions already work around the problem. These argument
materializations are going to be removed in a subsequent commit that
adds full 1:N support. The purpose of this PR is to add missing features
gradually in small increments.

This commit also updates two MLIR transformations that have their custom
workarounds around missing 1:N support. These can already start using
`replaceOpWithMultiple`.

Co-authored-by: Markus Böck <markus.boeck02@gmail.com>
2024-11-14 10:27:58 +09:00
Matthias Springer
f18c3e4e73
[mlir][Transforms] Dialect Conversion: Simplify materialization fn result type (#113031)
This commit simplifies the result type of materialization functions.

Previously: `std::optional<Value>`
Now: `Value`

The previous implementation allowed 3 possible return values:
- Non-null value: The materialization function produced a valid
materialization.
- `std::nullopt`: The materialization function failed, but another
materialization can be attempted.
- `Value()`: The materialization failed and so should the dialect
conversion. (Previously: Dialect conversion can roll back.)

This commit removes the last variant. It is not particularly useful
because the dialect conversion will fail anyway if all other
materialization functions produced `std::nullopt`.

Furthermore, in contrast to type conversions, at least one
materialization callback is expected to succeed. In case of a failing
type conversion, the current dialect conversion can roll back and try a
different pattern. This also used to be the case for materializations,
but that functionality was removed with #107109: failed materializations
can no longer trigger a rollback. (They can just make the entire dialect
conversion fail without rollback.) With this in mind, it is even less
useful to have an additional error state for materialization functions.

This commit is in preparation of merging the 1:1 and 1:N type
converters. Target materializations will have to return multiple values
instead of a single one. With this commit, we can keep the API simple:
`SmallVector<Value>` instead of `std::optional<SmallVector<Value>>`.

Note for LLVM integration: All 1:1 materializations should return
`Value` instead of `std::optional<Value>`. Instead of `std::nullopt`
return `Value()`.
2024-10-23 07:29:17 -07:00
Peiming Liu
f607102a0d
[mlir][sparse] partially support lowering sparse coiteration loops to scf.while/for. (#105565) 2024-08-23 10:47:44 -07:00
Peiming Liu
c44202574f
[mlir][sparse] support sparsification to coiterate operations. (#102546) 2024-08-20 11:13:38 -07:00
Peiming Liu
951a363097
[mlir][sparse] implement sparse_tensor.extract_value operation. (#101220) 2024-07-31 14:47:29 -07:00
Peiming Liu
a02010b3e9
[mlir][sparse] support sparsifying sparse kernels to sparse-iterator-based loop (#95858) 2024-06-17 16:50:12 -07:00
Peiming Liu
d6cc35f7f6
Reapply "[mlir][sparse] implement lowering rules for IterateOp." (#95836) 2024-06-17 13:29:53 -07:00
Shivam Gupta
bba5951b6f
[MLIR] Fix an assert that contains a mistake in conditional operator (#95668)
This is described in (N2) https://pvs-studio.com/en/blog/posts/cpp/1126/
so caught by the PVS Studio analyzer.

Warning message -
V502 Perhaps the '?:' operator works in a different way than it was
expected. The '?:' operator has a lower priority than the '+' operator.
LoopEmitter.cpp 983
V502 Perhaps the '?:' operator works in a different way than it was
expected. The '?:' operator has a lower priority than the '+' operator.
LoopEmitter.cpp 1039

The assert should be
assert(bArgs.size() == reduc.size() + (needsUniv ? 1 : 0));
since + has higher precedence and ? has lower.

This further can be reduce to
assert(aArgs.size() == reduc.size() + needsUniv);
because needUniv is a bool value which is implicitly converted to 0 or
2024-06-18 01:09:30 +05:30
Peiming Liu
996905d815
Revert "[mlir][sparse] implement lowering rules for IterateOp." (#95826)
Reverts llvm/llvm-project#95286
2024-06-17 11:35:23 -07:00
Peiming Liu
3a2e442893
[mlir][sparse] implement lowering rules for IterateOp. (#95286) 2024-06-17 10:45:50 -07:00
Peiming Liu
c42bbda425
[mlir][sparse] implement lowering rules for ExtractIterSpaceOp. (#89143)
**DO NOT MERGE** until https://github.com/llvm/llvm-project/pull/89003
2024-06-12 10:49:12 -07:00
Kazu Hirata
197c3a3efc
Use llvm::less_first (NFC) (#94136) 2024-06-02 07:45:50 -07:00
Yinying Li
e71eacc5b1
[mlir][sparse] Support explicit/implicit value for complex type (#90771) 2024-05-02 12:28:34 -04:00
Peiming Liu
78885395c8
[mlir][sparse] support tensor.pad on CSR tensors (#90687) 2024-05-01 15:37:38 -07:00
Peiming Liu
dbe376651a
[mlir][sparse] handle padding on sparse levels. (#90527) 2024-04-30 09:53:44 -07:00
Aart Bik
65ee8f10b2
[mlir][sparse] fold explicit value during sparsification (#90530)
This ensures the explicit value is generated (and not a load into the
values array). Note that actually not storing values array at all is
still TBD, this is just the very first step.
2024-04-29 18:06:07 -07:00
Peiming Liu
7e2eeb5753
[mlir][sparse] use ValueRange instead of std::pair for iterator position. (#90243)
`ValueRange` is more easy to be extended (e.g., for padded iterator).
2024-04-29 10:47:07 -07:00
Troy Butler
468fecfc39
Fix mismatches between function parameter definitions and declarations (#89512)
Addresses issue #88716.

Some function parameter names in the affected header files did not match
the parameter names in the definitions, or were listed in a different
order.

---------

Signed-off-by: Troy-Butler <squintik@outlook.com>
2024-04-26 13:00:31 +02:00
Christian Sigg
a5757c5b65
Switch member calls to isa/dyn_cast/cast/... to free function calls. (#89356)
This change cleans up call sites. Next step is to mark the member
functions deprecated.

See https://mlir.llvm.org/deprecation and
https://discourse.llvm.org/t/preferred-casting-style-going-forward.
2024-04-19 15:58:27 +02:00
Peiming Liu
a454d92c5a
[mlir][sparse] rename files and unifies APIs (#88162) 2024-04-09 10:59:15 -07:00
Peiming Liu
52b69aa32f
[mlir][sparse] support sparsifying batch levels (#83898) 2024-03-04 14:39:06 -08:00
Peiming Liu
1a0986f0f7
[mlir][sparse] code cleanup (using inferred type to construct to_[buf… (#83361)
…fer] op).
2024-02-28 16:55:28 -08:00