Skip to content

Make canonicalization patterns report failure when they change nothing - #323

Merged
ASDAlexander77 merged 1 commit into
mainfrom
normalize-cast-no-change-failure
Sep 14, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
normalize-cast-no-change-failure

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Problem

MLIR's greedy rewrite driver treats every successful pattern as an IR change: it sets changed = true (GreedyPatternRewriteDriver.cpp:626) and scans the region again, up to 10 times. Three of our canonicalization patterns returned success() even when they left the IR untouched:

  • NormalizeCast: for casts it does not rewrite (to any, union casts that need no tag, everything else)
  • RemoveUnused<T> (SymbolRef, Load, Undef, Null, ...): for ops that still have uses
  • RemoveUnusedAccessor<T>: for setters and used getters

So canonicalization never converged. On a ~30-line test, -debug-only=greedy-rewriter shows 714 false successes from NormalizeCast and 470 from RemoveUnused<LoadOp>, and every canonicalizer run ends with The pattern rewrite did not converge after scanning 10 times (9 times).

Fix

Each pattern now returns failure() unless it actually rewrote or erased the op.

Results

before after
operations processed by the driver (test above) 4523 699
"did not converge" warnings 9 0
00any.ts --emit=mlir-llvm, debug build, best of 3 1730 ms 1237 ms
00generator.ts, same 776 ms 566 ms

The emitted LLVM IR is identical for 00class, 00union_type, 00any, 00tuple, 00interface and 00generator. The only differing line is the embedded source path.

Tests

Full Windows debug suite: 2704/2721. The 17 failures are the same pre-existing set as on main (00funcs_generic_with_typeof, 01symbol, 00owned_array_ops under rc, gc-shared-auto, gc-defaultlib-collector); no new failures.

🤖 Generated with Claude Code

MLIR's greedy rewrite driver treats every successful pattern as an IR change
and re-scans the region, up to 10 times. NormalizeCast, RemoveUnused and
RemoveUnusedAccessor returned success even when they left the IR untouched
(a cast they do not rewrite, an op that still has uses), so canonicalization
never converged: on a small test every canonicalizer run hit the iteration
limit ("did not converge after scanning 10 times", 9 times), with 714 false
successes from NormalizeCast and 470 from RemoveUnused<LoadOp> alone.

They now return failure when nothing was rewritten or erased. On that test the
driver processes 699 operations instead of 4523, with no convergence warnings.
The emitted LLVM IR is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 73fbf09 into main Sep 14, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the normalize-cast-no-change-failure branch September 14, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant