1715 Commits

Author SHA1 Message Date
Scott Manley
370a571597
[RegionUtils] replace uses in nested regions when isolating from above (#180548)
When making a region IsolatedFromAbove, replace uses in any region
within the parent region, not just the immediate parent region.
2026-02-10 07:36:47 -06:00
Jorn Tuyls
f84c3672c3
[mlir] Extend moveValueDefinitions/moveOperationDependencies with cross-region support (#176343)
Extends `moveValueDefinitions` and `moveOperationDependencies` to
support moving operations across basic blocks and out of nested regions
2026-02-02 11:39:02 +01:00
Sladyn
49e3ae6f7b
Use reportFatalInternalError in DialectConversion (#178612)
Migrate from deprecated report_fatal_error to reportFatalInternalError
in DialectConversion.cpp. All 6 instances are internal consistency
checks in MLIR's dialect conversion system, so reportFatalInternalError
is the appropriate replacement.

Part of #138914
2026-02-01 22:10:26 +01:00
Jakub Kuderski
9aaf0b89f5
[mlir] Apply clang-tidy check llvm-use-vector-utils. NFC. (#178526) 2026-01-29 02:19:00 +00:00
Lukas Sommer
c1152f0fb2
[mlir] Avoid segfault in 'MoveBlockRewrite' rollback (#178148)
Prior to this change, rollback of the `MoveBlockRewrite` could result in
segfault if the block wasn't contained in a region anymore.

That situation could arise if the previous rollback of another rewrite
orphaned the block by removing it from its region, as demonstrated by
the new test pattern.

Signed-off-by: Lukas Sommer <lukas.sommer@amd.com>
2026-01-27 15:06:57 +01:00
Jorn Tuyls
5faa181112
[mlir] Add side-effect check to moveOperationDependencies (#176361)
This patch adds a side-effect check to `moveOperationDependencies` to
match the behavior of `moveValueDefinitions`. Previously,
`moveOperationDependencies` would move operations with side-effecting
dependencies, which could change program semantics.

**Note** that the existing test changes are needed because unregistered
operations (e.g., "moved_op"()) are treated as side-effecting. These
tests were updated to use pure operations for operations in the moved
slice, while keeping unregistered ops for operations that aren't moved
(e.g., "before"(), "foo"()). This ensures that tests continue to
exercise their intended functionality without being blocked by the new
side-effect check.
2026-01-23 14:10:42 +01:00
Matthias Springer
4a880833b7
[mlir][NFC] remove-dead-values: Get canonicalization patterns from ops (#176712)
Collect canonicalization patterns from the region branch ops (instead of
populating all canonicalization patterns).

Addresses a
[comment](https://github.com/llvm/llvm-project/pull/173505#discussion_r2675222999)
on a merged PR.
2026-01-19 10:30:19 +01:00
Matthias Springer
82c1f9435d
[mlir][Transforms] remove-dead-values: Rely on canonicalizer for region simplification (#173505)
This commit simplifies the `remove-dead-values` pass and fixes a bug in
the handling of `RegionBranchOpInterface` ops. The pass used to produce
invalid IR ("null value found") for the newly added test case.

`remove-dead-values` is a pass for additional IR simplification that
cannot be performed by the canonicalizer pass. Based on a liveness
analysis, it erases dead values / IR. (The liveness analysis is a
dataflow analysis that has more information about the IR than a
canonicalization pattern, which can see only "local" information.)

Region-based ops are difficult. The liveness analysis may determine that
an SSA value is dead. However, that does not mean that the value can
actually be removed. Doing so may violate an region data flow (as
modeled by the `RegionBranchOpInterface`). As an example, consider the
case where a region branch terminator may dispatch to one of two region
successor with the same forwarded values. A successor input (block
argument) can be erased only if it is dead on both successors.

Before this commit, there used to be complex logic to determine when it
is safe to erase an SSA value. That logic was broken. The new
implementation does not remove any block arguments or op results of
region-based ops. Instead, operands of region-based ops and region
branch terminators are replaced with `ub.poison` if all of their
successor values are dead. This simplifies the IR good enough for the
canonicalizer to perform the remaining region simplification (i.e.,
dropping block arguments etc.).

RFC:
https://discourse.llvm.org/t/rfc-delegate-simplification-of-region-based-ops-from-remove-dead-values-to-canonicalizer/89194
2026-01-07 14:51:40 +01:00
Ben Vanik
4ac6431755
[mlir] Fix crash in dropRedundantArguments with produced operands. (#172759)
dropRedundantArguments was incorrectly indexing into forwardedOperands
using the block argument index directly. This crashes when the block has
produced operands (generated by the terminator, not forwarded from
predecessors) because forwardedOperands doesn't include them.

The fix checks isOperandProduced() to skip produced arguments and uses
SuccessorOperands::operator[] which handles the offset correctly.
2026-01-06 22:53:28 -08:00
Victor Chernyakin
c438773432
[LLVM][ADT] Migrate users of make_scope_exit to CTAD (#174030)
This is a followup to #173131, which introduced the CTAD functionality.
2026-01-02 20:42:56 -08:00
Matthias Springer
7de3fb53ce
[mlir][Transforms][NFC] remove-dead-values: Erase ops at the end (#174208)
`remove-dead-values` performs various cleanups:
1. Erasing block arguments
2. Erasing successor operands
3. Erasing operations
4. Erasing function arguments / results
5. Erasing operands
6. Erasing results

This commit moves Step 3 (erasing operations) to the end. While that
does not fix any bugs by itself, it is potentially safer. If an
operation is erased, we must be careful that the operation is not
accessed in the following steps. That can no longer happen if IR is
erased only in the final step and not before.

This commit is prefetching a change from #173505 (to keep that PR
shorter). With #173505, it will become necessary to erase IR in the
final step.
2026-01-02 14:48:26 +01:00
Matthias Springer
cf9b3bbb09
[mlir][IR][NFC] Add RewriterBase::eraseOpResults convenience helper (#174152)
There are various places in the code base where op results are removed.
E.g., some canonicalization patterns remove op results. This commit adds
a new helper function to `RewriterBase` to reduce code duplication and
simplify patterns. The existing implementation from
`RemoveDeadValues.cpp` is moved into the rewriter API.

There is now a uniform API for removing operands and values:
* `Block::eraseArguments(BitVector)`
* `Operation::eraseOperands(BitVector)`
* NEW: `RewriterBase::eraseOpResults(Operation *, BitVector)`

This commit is preparation of adding new canonicalizations for
region-based ops, which will add yet another place where op results must
be erased.
2026-01-02 11:56:32 +00:00
Matthias Springer
8e86107b1f
[mlir][IR][NFC] Add Block::computeBlockNumber convenience helper (#173475)
Add a helper function to compute the number of a block. Recommended only
for debugging purposes and to print error messages.
2025-12-30 13:43:51 +00:00
Matthias Springer
60606b22a7
[mlir][Interfaces] Add RegionBranchOpInterface::getSuccessorOperands helper (#173971)
Add a helper for querying the successor operands for a region branch
`src -> dst`. Both `src` and `dst` may be the region branch op itself or
a terminator.

This helper allows users to query successor operands for the region
branch op and the terminators in a uniform way. This is similar to
`getSuccessorRegions(RegionBranchPoint)`, which works both for region
branch ops and terminators.
2025-12-30 12:28:02 +01:00
Matthias Springer
ca73d19030
[mlir][Transforms][NFC] remove-dead-values: Simplify dropped value handling (#173540)
`RDVFinalCleanupList::values` is used only for function op handling. The
functionality for dropping function arg uses can be incorporated into
Step 5 (function op handling). There is no need for a separate step.
2025-12-30 09:22:58 +01:00
Matthias Springer
7c2bbfae3e
[mlir][Transforms][NFC] remove-dead-values: Split OperationToCleanup (#173542)
The `callee` field does not make sense for op results. Split
`OperationToCleanup` into `OperandsToCleanup` and `ResultsToCleanup`.
2025-12-26 12:44:23 +01:00
Matthias Springer
352bf3d78b
[mlir][Transforms][NFC] remove-dead-values: Use proper rewriter API (#173539)
Use the rewriter API to inline regions.
2025-12-26 12:28:39 +01:00
Matthias Springer
643c5c0fb6
[mlir][Transforms][NFC] Improve debug output of -remove-dead-values (#173468)
Print the index of the block arguments, op results etc. that are being
removed.
2025-12-24 10:31:45 +00:00
Matthias Springer
78711b66bd
[mlir][Transforms] Legalize nested operations (#172158)
This commit align the implementation of
`ConversionPatternRewriter::legalize` with its documentation:

```
  /// Attempt to legalize the given region. This can be used within
  ...
  LogicalResult legalize(Region *r);
```

This function now legalizes the entire region, including nested ops. The
implementation follows the same logic as the "main" traversal:
pre-order, forward-dominance.
2025-12-16 16:47:47 +01:00
Mehdi Amini
f5c28bdaa6 [MLIR] Apply clang-tidy fixes for misc-use-internal-linkage in ViewOpGraph.cpp (NFC) 2025-12-10 09:45:24 -08:00
Mehdi Amini
d796d73631 [MLIR] Apply clang-tidy fixes for readability-identifier-naming in Inliner.cpp (NFC) 2025-12-09 10:15:02 -08:00
Quinn Dawkins
bb17dfa7d1
[mlir][bufferization] Enable moving dependent values in eliminate-empty-tensors (#169718)
Currently empty tensor elimination by constructing a SubsetExtractionOp
to match a SubsetInsertionOp at the end of a DPS chain will fail if any
operands required by the insertion op don't dominate the insertion point
for the extraction op.

This change improves the transformation by attempting to move all pure
producers of required operands to the insertion point of the extraction
op. In the process this improves a number of tests for empty tensor
elimination.
2025-12-05 14:40:08 -05:00
AidinT
41f00cb3de
[MLIR] feat(mlir-tblgen): Add support for dialect interfaces (#170046)
Currently, Dialect Interfaces can't be defined in ODS. This PR adds the
support for dialect interfaces. It follows the same approach with other
interfaces and extends on top of `Interface` class defined in
`mlir/TableGen/Interfaces.h`.

Given the following input:

```tablegen
#ifndef MY_INTERFACES
#define MY_INTERFACES

include "mlir/IR/Interfaces.td"

def DialectInlinerInterface : DialectInterface<"DialectInlinerInterface"> {
  let description = [{
     Define a base inlining interface class to allow for dialects to opt-in to the inliner.
  }];

  let cppNamespace = "::mlir";

  let methods = [
    InterfaceMethod<
      /*desc=*/        [{
        Returns true if the given region 'src' can be inlined into the region
        'dest' that is attached to an operation registered to the current dialect.
        'valueMapping' contains any remapped values from within the 'src' region.
        This can be used to examine what values will replace entry arguments into
        the 'src' region, for example.
      }],
      /*returnType=*/  "bool",
      /*methodName=*/  "isLegalToInline",
      /*args=*/        (ins "::mlir::Region *":$dest, "::mlir::Region *":$src, "::mlir::IRMapping &":$valueMapping),
      /*methodBody=*/  [{
        return true;
      }]
      >
  ];
}


#endif
```

It will generate the following code:

```cpp
/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\
|*                                                                            *|
|* Dialect Interface Declarations                                             *|
|*                                                                            *|
|* Automatically generated file, do not edit!                                 *|
|*                                                                            *|
\*===----------------------------------------------------------------------===*/

namespace mlir {

/// Define a base inlining interface class to allow for dialects to opt-in to the inliner.
class DialectInlinerInterface : public ::mlir::DialectInterface::Base<DialectInlinerInterface> {
public:

  /// Returns true if the given region 'src' can be inlined into the region
  /// 'dest' that is attached to an operation registered to the current dialect.
  /// 'valueMapping' contains any remapped values from within the 'src' region.
  /// This can be used to examine what values will replace entry arguments into
  /// the 'src' region, for example.
  virtual bool isLegalToInline(::mlir::Region * dest, ::mlir::Region * src, ::mlir::IRMapping & valueMapping) const;

protected:
  DialectInlinerInterface(::mlir::Dialect *dialect) : Base(dialect) {}
};

} // namespace mlir

bool ::mlir::DialectInlinerInterface::isLegalToInline(::mlir::Region * dest, ::mlir::Region * src, ::mlir::IRMapping & valueMapping) const {
  return true;
}
```
2025-12-05 08:10:51 -08:00
Matthias Springer
e6110cb339
[mlir][Transforms] Fix crash in -remove-dead-values on private functions (#169269)
This commit fixes two crashes in the `-remove-dead-values` pass related
to private functions.

Private functions are considered entirely "dead" by the liveness
analysis, which drives the `-remove-dead-values` pass.

The `-remove-dead-values` pass removes dead block arguments from private
functions. Private functions are entirely dead, so all of their block
arguments are removed. However, the pass did not correctly update all
users of these dropped block arguments.

1. A side-effecting operation must be removed if one of its operands is
dead. Otherwise, the operation would end up with a NULL operand. Note:
The liveness analysis would not have marked an SSA value as "dead" if it
had a reachable side-effecting users. (Therefore, it is safe to erase
such side-effecting operations.)
2. A branch operation must be removed if one of its non-forwarded
operands is dead. (E.g., the condition value of a `cf.cond_br`.)
Whenever a terminator is removed, a `ub.unrechable` operation is
inserted. This fixes #158760.
2025-12-03 08:35:05 +01:00
Matthias Springer
504b507896
[mlir][Transforms] Dialect conversion: Add support for replaceUsesWithIf (#169606)
This commit adds support for `replaceUsesWithIf` (and variants such as
`replaceAllUsesExcept`) to the `ConversionPatternRewriter`. This API is
supported only in no-rollback mode. An assertion is triggered in
rollback mode. (This missing assertion has been confusing for users
because it seemed that the API supported, while it was actually not
working properly.)

This commit brings us a bit closer towards removing
[this](76ec25f729/mlir/lib/Transforms/Utils/DialectConversion.cpp (L1214))
workaround.

Additional changes are needed to support this API in rollback mode. In
particular, no entries should be added to the `ConversionValueMapping`
for conditional replacements. It's unclear at this point if this API can
be supported in rollback mode, so this is deferred to later.

This commit turns `replaceUsesWithIf` into a virtual function, so that
the `ConversionPatternRewriter` can override it. All other API functions
for conditional value replacements call that function.

Note for LLVM integration: If you are seeing failed assertions due to
this change, you are using unsupported API in your dialect conversion.
You have 3 options: (1) Migrate to the no-rollback driver. (2) Rewrite
your patterns without the unsupported API. (3) Last resort: bypass the
rewriter and call `replaceUsesWithIf` etc. directly on the `Value`
object.
2025-11-27 01:54:07 +00:00
lonely eagle
765208b313
[mlir] Make remove-dead-values remove block and successorOperands before delete ops (#166766)
Reland https://github.com/llvm/llvm-project/pull/165725, fix the Failed
test by removing successor operands before delete operations. Following
the deletion of cond.branch, its successor operands will subsequently be
removed.
2025-11-20 13:55:09 +08:00
Vadim Curcă
e992280f9d
[MLIR] Fix empty optional access in DialectConversion (#168331)
When both `MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS` and MLIR
multithreading are enabled, `topLevelFingerPrint` is empty but its value
is accessed. This adds a `has_value()` check before dereferencing the
optional.
2025-11-17 11:18:34 +01:00
Mehdi Amini
938f521e40 [MLIR] Apply clang-tidy fixes for performance-unnecessary-value-param in DialectConversion.cpp (NFC) 2025-11-11 06:59:29 -08:00
Tim Noack
f22d5884b2
[mlir] Dialect Conversion: Fix expensive pattern check in no-rollback mode (#166576)
Fixes a bug causing every conversion to fail fatally with "expected
pattern to replace the root operation or modify it in place" when
`MLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS` is enabled and pattern
rollback is disabled.

When `allowPatternRollback` is disabled, the rewriter does not keep
track of the rewrites it performs and can therefore not use that list to
check whether the root op was replaced or updated in place.
2025-11-10 12:45:31 +00:00
lonely eagle
55fb1caf8a
Revert "[mlir] Make remove-dead-values pass remove blocks arguments first" (#166746)
Reverts llvm/llvm-project#165725. See
https://lab.llvm.org/buildbot/#/builders/169/builds/16768,
2025-11-06 11:03:19 +00:00
lonely eagle
a928c61961
[mlir] Make remove-dead-values pass remove blocks arguments first (#165725)
Fix https://github.com/llvm/llvm-project/issues/163051. Some Ops which
have multiple blocks, before deleting the ops, first remove the dead
parameters within its blocks.
2025-11-06 16:36:14 +08:00
Matthias Springer
a38e094240
[mlir] Dialect Conversion: Add support for post-order legalization order (#166292)
By default, the dialect conversion driver processes operations in
pre-order: the initial worklist is populated pre-order. (New/modified
operations are immediately legalized recursively.)

This commit adds a new API for selective post-order legalization.
Patterns can request an operation / region legalization via
`ConversionPatternRewriter::legalize`. They can call these helper
functions on nested regions before rewriting the operation itself.

Note: In rollback mode, a failed recursive legalization typically leads
to a conversion failure. Since recursive legalization is performed by
separate pattern applications, there is no way for the original pattern
to recover from such a failure.
2025-11-05 21:04:32 +09:00
Matthias Springer
d4c41b7fa3
[mlir][Transforms] Dialect Conversion: Convert entry block only (#165180)
When converting a function, convert only the entry block signature. The
remaining block signatures should be converted by the respective
branching ops. The `FuncToLLVM` / `ControlFlowToLLVM` patterns already
use that design.

```c++
struct BranchOpLowering : public ConvertOpToLLVMPattern<cf::BranchOp> {

  LogicalResult
  matchAndRewrite(cf::BranchOp op, OneToNOpAdaptor adaptor,
                  ConversionPatternRewriter &rewriter) const override {
    // Convert successor block.
    SmallVector<Value> flattenedAdaptor = flattenValues(adaptor.getOperands());
    FailureOr<Block *> convertedBlock =
        getConvertedBlock(rewriter, getTypeConverter(), op, op.getSuccessor(),
                          TypeRange(ValueRange(flattenedAdaptor)));
    // ...
  }
};
```

This is consistent with the fact that operations from unreachable blocks
are not put on the initial worklist.

With this change, parent ops are no longer recursively legalized when
inserting a block, simplifying the conversion driver a bit.

Note for LLVM integration: If you are seeing failures, make sure to:
- Drop `converter.isLegal(&op.getBody())` when checking the legality of
a function op. Only the entry block signature / function type should be
taken into account.
- If you need to convert all reachable blocks and are using `cf`
branching ops, add `populateCFStructuralTypeConversionsAndLegality`.
- If you need to convert all reachable blocks and are using custom
branching ops, implement and populate custom structural type conversion
patterns, similar to `populateCFStructuralTypeConversionsAndLegality`.
2025-11-03 23:34:52 +00:00
Mehdi Amini
a8abf813eb [MLIR] Apply clang-tidy fixes for performance-unnecessary-value-param in ViewOpGraph.cpp (NFC) 2025-10-30 21:44:21 -07:00
Mehdi Amini
41f65666f6
[MLIR] Revamp RegionBranchOpInterface (#165429)
This is still somehow a WIP, we have some issues with this interface
that are not trivial to solve. This patch tries to make the concepts of
RegionBranchPoint and RegionSuccessor more robust and aligned with their
definition:
- A `RegionBranchPoint` is either the parent (`RegionBranchOpInterface`)
op or a `RegionBranchTerminatorOpInterface` operation in a nested
region.
- A `RegionSuccessor` is either one of the nested region or the parent
`RegionBranchOpInterface`

Some new methods with reasonnable default implementation are added to
help resolving the flow of values across the RegionBranchOpInterface.

It is still not trivial in the current state to walk the def-use chain
backward with this interface. For example when you have the 3rd block
argument in the entry block of a for-loop, finding the matching operands
requires to know about the hidden loop iterator block argument and where
the iterargs start. The API is designed around forward-tracking of the
chain unfortunately.

Try to reland #161575 ; I suspect a buildbot incremental build issue.
2025-10-28 09:53:56 -07:00
Mehdi Amini
e3c547179f
Revert " [MLIR] Revamp RegionBranchOpInterface " (#165356)
Reverts llvm/llvm-project#161575

Broke Windows on ARM buildbot build, needs investigations.
2025-10-28 01:06:14 -07:00
Mehdi Amini
ab1fd21b54
[MLIR] Revamp RegionBranchOpInterface (#161575)
This is still somehow a WIP, we have some issues with this interface
that are not trivial to solve. This patch tries to make the concepts of
RegionBranchPoint and RegionSuccessor more robust and aligned with their
definition:
- A `RegionBranchPoint` is either the parent (`RegionBranchOpInterface`)
op or a `RegionBranchTerminatorOpInterface` operation in a nested
region.
- A `RegionSuccessor` is either one of the nested region or the parent
`RegionBranchOpInterface`

Some new methods with reasonnable default implementation are added to
help resolving the flow of values across the RegionBranchOpInterface.

It is still not trivial in the current state to walk the def-use chain
backward with this interface. For example when you have the 3rd block
argument in the entry block of a for-loop, finding the matching operands
requires to know about the hidden loop iterator block argument and where
the iterargs start. The API is designed around forward-tracking of the
chain unfortunately.
2025-10-28 07:47:26 +00:00
lonely eagle
2e11538ab9
[mlir] Use isPure and skipRegions to print region op (NFC) (#163422) 2025-10-15 01:30:53 +08:00
Hanchenng Wu
4e6ee0b674
[MLIR] Fix test failures for generate-runtime-verification pass from PR #160331 (#162533)
[MLIR] Fix test failures for generate-runtime-verification pass from PR #160331
    
PR #160331 introduced a mistake that removed the error message for
generate-runtime-verification
pass, leading to test failures during
`test-build-check-mlir-build-only-check-mlir`.
    
This patch restores the missing error message.
    
In addition, for related tests, the op strings used in FileChecks are
updated with the same op
formats as used in input mlirs.
    
Verified locally.
    
Fixes post-merge regression from:
https://github.com/llvm/llvm-project/pull/160331
2025-10-08 23:31:55 +01:00
Hanchenng Wu
a6d1a52b8d
[MLIR] Reuse AsmState to enable fast generate-runtime-verification pass; add location-only pass option (#160331)
The pass generate-runtime-verification generates additional runtime op
verification checks.

Currently, the pass is extremely expensive. For example, with a
mobilenet v2 ssd network(converted to mlir), running this pass alone in
debug mode will take 30 minutes. The same observation has been made to
other networks as small as 5 Mb.

The culprit is this line "op->print(stream, flags);" in function
"RuntimeVerifiableOpInterface::generateErrorMessage" in File
mlir/lib/Interfaces/RuntimeVerifiableOpInterface.cpp.

As we are printing the op with all the names of the operands in the
middle end, we are constructing a new SSANameState for each
op->print(...) call. Thus, we are doing a new SSA analysis for each
error message printed.

Perf profiling shows that 98% percent of the time is spent in the
constructor of SSANameState.

This change refactored the message generator. We use a toplevel
AsmState, and reuse it with all the op-print(stream, asmState). With a
release build, this change reduces the pass exeuction time from ~160
seconds to 0.3 seconds on my machine.

This change also adds verbose options to generate-runtime-verification
pass.
verbose 0: print only source location with error message.
verbose 1: print the full op, including the name of the operands.
2025-10-08 11:48:34 +01:00
Matthias Springer
83c135cad3
[mlir] Dialect conversion: Print note when replacement types do not match legalized types (#161802)
When running with `-debug`, print a note when the replacement types
(during a `ConversionPatternRewriter::replaceOp`) do not match the
legalized types of the current type converter. That's not an API
violation, but it could indicate a bug in user code.

Example output:
```
[dialect-conversion:1]     ** Replace : 'test.multiple_1_to_n_replacement'(0x56b745f99470)
[dialect-conversion:1]        Note: Replacing op result of type f16 with value(s) of type (f16, f16), but the legalized type(s) is/are (f16)
```
2025-10-03 16:39:01 +02:00
Mehdi Amini
6167f0c818 [MLIR] Apply clang-tidy fixes for llvm-qualified-auto in Mem2Reg.cpp (NFC) 2025-09-28 04:29:19 -07:00
Mehdi Amini
fcf79e5276
[MLIR] Improve in-place folding to iterate until fixed-point (#160615)
When executed in the context of canonicalization, the folders are
invoked in a fixed-point iterative process. However in the context of an
API like `createOrFold()` or in DialectConversion for example, we expect
a "one-shot" call to fold to be as "folded" as possible. However, even
when folders themselves are indempotent, folders on a given operation
interact with each other. For example:

```
// X = 0 + Y
%X = arith.addi %c_0, %Y : i32
```

should fold to %Y, but the process actually involves first the folder
provided by the IsCommutative trait to move the constant to the right.
However this happens after attempting to fold the operation and the
operation folder isn't attempt again after applying the trait folder.

This commit makes sure we iterate until fixed point on folder
applications.

Fixes #159844
2025-09-27 10:29:42 +02:00
Mehdi Amini
7ab7bc7274
[MLIR] Fix LivenessAnalysis/RemoveDeadValues handling of dead function arguments (#160755)
In #153973 I added the correctly handling of block arguments,
unfortunately this was gated on operation that also have results. This
wasn't intentional and this excluded operations like function from being
correctly processed.
2025-09-26 13:47:46 +00:00
Francisco Geiman Thiesen
3e746bd8fb
Allowing RDV to call getArgOperandsMutable() (#160415)
## Problem

`RemoveDeadValues` can legally drop dead function arguments on private
`func.func` callees. But call-sites to such functions aren't fixed if
the call operation keeps its call arguments in a **segmented operand
group** (i.ie, uses `AttrSizedOperandSegments`), unless the call op
implements `getArgOperandsMutable` and the RDV pass actually uses it.

## Fix
When RDV decides to drop callee function args, it should, for each
call-site that implements `CallOpInterface`, **shrink the call's
argument segment** via `getArgOperandsMutable()` using the same dead-arg
indices. This keeps both the flat operand list and the
`operand_segment_sizes` attribute in sync (that's what
`MutableOperandRange` does when bound to the segment).

## Note
This change is a no-op for:
* call ops without segment operands (they still get their flat operands
erased via the generic path)
* call ops whose calle args weren't dropped (public, external,
non-`func-func`, unresolved symbol, etc)
* `llvm.call`/`llvm.invoke` (RDV doesn't drop `llvm.func` args

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
2025-09-26 15:30:46 +02:00
Fabian Mora
077a796c0d
[mlir] Implement a memory-space cast bubbling-down transform (#159454)
This commit adds functionality to bubble down memory-space casts
operations, allowing consumer operations to use the original
memory-space rather than first casting to a different memory space.

Changes:
- Introduce `MemorySpaceCastOpInterface` to handle memory-space cast
operations
- Create a `MemorySpaceCastConsumerOpInterface` pass that identifies and
bubbles down eligible casts
- Add implementation for memref and vector operations to handle
memory-space cast propagation
- Add `bubbleDownCasts` method to relevant operations to support the
fusion

In particular, in the current implementation only memory-space casts
into the default memory-space can be bubbled-down.

Example:

```mlir
func.func @op_with_cast_sequence(%arg0: memref<4x4xf32, 1>, %arg1: index, %arg2: f32) -> memref<16xf32> {
    %memspacecast = memref.memory_space_cast %arg0 : memref<4x4xf32, 1> to memref<4x4xf32>
    %c0 = arith.constant 0 : index
    %c4 = arith.constant 4 : index
    %expanded = memref.expand_shape %memspacecast [[0], [1, 2]] output_shape [4, 2, 2] : memref<4x4xf32> into memref<4x2x2xf32>
    %collapsed = memref.collapse_shape %expanded [[0, 1, 2]] : memref<4x2x2xf32> into memref<16xf32>
    %loaded = memref.load %collapsed[%c0] : memref<16xf32>
    %added = arith.addf %loaded, %arg2 : f32
    memref.store %added, %collapsed[%c0] : memref<16xf32>
    %atomic_result = memref.atomic_rmw addf %arg2, %collapsed[%c4] : (f32, memref<16xf32>) -> f32
    return %collapsed : memref<16xf32>
}
// mlir-opt --bubble-down-memory-space-casts
func.func @op_with_cast_sequence(%arg0: memref<4x4xf32, 1>, %arg1: index, %arg2: f32) -> memref<16xf32> {
    %c4 = arith.constant 4 : index
    %c0 = arith.constant 0 : index
    %expand_shape = memref.expand_shape %arg0 [[0], [1, 2]] output_shape [4, 2, 2] : memref<4x4xf32, 1> into memref<4x2x2xf32, 1>
    %collapse_shape = memref.collapse_shape %expand_shape [[0, 1, 2]] : memref<4x2x2xf32, 1> into memref<16xf32, 1>
    %memspacecast = memref.memory_space_cast %collapse_shape : memref<16xf32, 1> to memref<16xf32>
    %0 = memref.load %collapse_shape[%c0] : memref<16xf32, 1>
    %1 = arith.addf %0, %arg2 : f32
    memref.store %1, %collapse_shape[%c0] : memref<16xf32, 1>
    %2 = memref.atomic_rmw addf %arg2, %collapse_shape[%c4] : (f32, memref<16xf32, 1>) -> f32
    return %memspacecast : memref<16xf32>
}
```

---------

Signed-off-by: Fabian Mora <fabian.mora-cordero@amd.com>
Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
2025-09-24 09:11:43 -04:00
Matthias Springer
96a3a58e18
[mlir][Transforms] Simplify ConversionPatternRewriter::replaceOp implementation (#158075)
Move the logic for building "out-of-thin-air" source materializations
during op replacements from `replaceOp` to
`findOrBuildReplacementValue`. That function already builds source
materializations and can handle the case where an op result is dropped.

This commit is in preparation of turning `replaceOp` into a non-virtual
function. (It is sufficient for `replaceAllUsesWith` and `eraseOp` to be
virtual.)
2025-09-22 13:49:03 +02:00
Mehdi Amini
322b990267 [MLIR] Apply clang-tidy fixes for llvm-qualified-auto in CompositePass.cpp (NFC) 2025-09-21 23:56:31 -07:00
Mehdi Amini
8245fb687a [MLIR] Apply clang-tidy fixes for llvm-qualified-auto in GreedyPatternRewriteDriver.cpp (NFC) 2025-09-21 23:54:59 -07:00
Matthias Springer
3c862b4ba3
[mlir] Expose optional PatternBenefit to function / SCF populate functions (NFC) (#159752)
Pattern benefit allows users to give priority to a pattern.
2025-09-19 13:46:04 +02:00