Skip to content

Fix invalid multibroadcast shapes for shared reductions - #5360

Closed
urpetkov-amd wants to merge 6 commits into
developfrom
fix_multibroadcast_apo
Closed

urpetkov-amd wants to merge 6 commits into
developfrom
fix_multibroadcast_apo

Conversation

@urpetkov-amd

Copy link
Copy Markdown
Collaborator

Motivation

Fix invalid MULTIBROADCAST shapes when compiling Topaz APF, APO, AIOB, and AION models.

The simplify_reshapes pass could move an element-expanding shape-transform chain through a shared reduction. Because the rewrite replaces the reduction globally, its other consumers received an incompatible shape.

Technical Details

  • Restrict element-expanding reduction rewrites to reductions with a single consumer.
  • Preserve existing rewrites when the element count does not change.
  • Add op_shape_transform_shared_reduce_expanding_chain to cover a shared reduce_mean with an expanding shape-transform chain.
  • Add the fix as the first entry under the Develop changelog's Resolved issues section.

This regression became reachable after the matcher changes in #5233.

Changelog Category

Add a CHANGELOG.md entry for any option other than Not Applicable

    • Added: New functionality.
    • Changed: Changes to existing functionality.
    • Removed: Functionality or support that has been removed. (Compared to a previous release)
    • Optimized: Component performance that has been optimized or improved.
    • Resolved Issues: Known issues from a previous version that have been resolved.
    • Not Applicable: This PR is not to be included in the changelog.

Follow the LLVM AI Tool Use Policy for contributions using AI.

@urpetkov-amd
urpetkov-amd requested review from a team and causten as code owners October 7, 2026 12:17
@urpetkov-amd
urpetkov-amd requested review from TedThemistokleous, causten and pfultz2 and removed request for a team and causten October 7, 2026 13:35
Comment thread src/simplify_reshapes.cpp
// An element-expanding chain can be moved through a reduction only when
// the reduction is not shared. The rewrite replaces x_ins globally, so
// changing its shape would invalidate its other consumers.
return is_reduce(x_ins) and x_ins->outputs().size() == 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already insert a reshape back to the source for other consumers.

We reshape back to the src here:

auto new_x_ins = reshape_input(x_ins, desc.to_src_from_common())(new_input_ins);

And then replace x_ins with this reshaped input:

m.replace_instruction(x_ins, new_x_ins);

So there shouldn't be incompatible shapes.

@urpetkov-amd urpetkov-amd Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right that the pass intends to reshape back before replacing x_ins. The failure occurs before replace_instruction is reached.

For the failing expanding chain, to_src_from_common() generates a multibroadcast from {1,1,1,1,6} to {1,1,1,2,3}, which is invalid. I kept the shared-reduction guard because shared consumers require restoring the original output. For a single-consumer reduction, that restoration is unnecessary.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this will still bail even when to_src_common does work.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The guard addresses the global replacement risk and has focused regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Prevents simplify_reshapes from invalidating other consumers of shared reductions.

Changes:

  • Gates element-expanding rewrites on single-consumer reductions.
  • Adds regression coverage and a changelog entry.
File Description
src/​simplify_reshapes.cpp Adds the consumer-count guard.
test/​simplify_reshapes_test.cpp Tests a shared expanding reduction chain.
CHANGELOG.md Documents the resolved issue.

Review was single-pass without agent fan-out; runtime tests were not executed.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #5360   +/-   ##
========================================
  Coverage    92.71%   92.71%           
========================================
  Files          635      635           
  Lines        36236    36239    +3     
========================================
+ Hits         33595    33598    +3     
  Misses        2641     2641           
Files with missing lines Coverage Δ
src/simplify_reshapes.cpp 97.88% <100.00%> (+0.01%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

auto image = m1.add_parameter("image", {migraphx::shape::float_type, {1, 384, 480, 3}});
auto scale = m1.add_parameter("scale", {migraphx::shape::float_type, {1, 1, 1, 2, 3}});
auto mean = m1.add_instruction(migraphx::make_op("reduce_mean", {{"axes", {1, 2}}}), image);
auto unsqueeze = m1.add_instruction(migraphx::make_op("unsqueeze", {{"axes", {3}}}), mean);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unsqueeze should be remove here as well.

@pfultz2

pfultz2 commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

So I opened #5365 to address these issues as this requires changes to the shape_transform_descriptor.

@urpetkov-amd

Copy link
Copy Markdown
Collaborator Author

@pfultz2
Thanks a lot. I was preparing to ask you should I:

  1. skip inverse restoration for single-consumer reductions
  2. for shared reductions continue only when to_src_from_common() is valid
  3. bail only for invalid inverse transforms such as these Topaz case

or you have in mind some better or simpler approach, now I see your PR and changes you made and they are fixing the problem I assume, I'll test with them to confirm it.

@urpetkov-amd

urpetkov-amd commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

This has been fixed by #PR5365

pfultz2 added a commit that referenced this pull request Oct 11, 2026
…eeze into multibroadcast (#5365)

`simplify_reshapes` moves a shape-transform chain between a reduction and a pointwise op into a common space so the two can fuse. When the chain broadcasts a new axis (for example `reduce_mean -> unsqueeze -> multibroadcast -> mul`), the pass rebuilt the old reduction for its other consumers with `to_src_from_common()`, which produced an invalid `reshape` because the broadcasted axis has no source axis to map back to. The result was a `MULTIBROADCAST: input shape {1, 1, 1, 1, 6} cannot be broadcasted` error at compile time (#5360).

While fixing this, the `unsqueeze -> multibroadcast` chain itself turned out to be redundant: `multibroadcast` aligns from the right, so an unsqueezed axis that only follows 1s is added by the broadcast. Folding it exposes the reduction to the pass as a bare broadcast, which previously was always skipped, so the descriptor also needs to tell a broadcast of a new axis apart from a re-broadcast of a reduced axis.
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.

3 participants