Lower reshape after eliminate_contiguous in a single pass - #5105
Lower reshape after eliminate_contiguous in a single pass#5105ivarusic-amd wants to merge 13 commits into
Conversation
Lower reshapes after contiguous elimination so layout decisions are validated locally and invalid lazy views fall back to safe copies. Co-authored-by: Cursor <cursoragent@cursor.com>
… a gpu::contiguous that reports the wrong shape
|
@ivarusic-amd what model are we seeing this in? Just message me in teams |
Regressions detected 🔴 * No develop baseline was found for this PR's branch point; compared against the latest available develop run instead. |
|
148a931 to
1ab2a09
Compare
…dentity permutation
Co-authored-by: Cursor <cursoragent@cursor.com>
Affecting |
|
|
||
| struct find_reshape : match::supports_dynamic_shapes | ||
| { | ||
| auto matcher() const { return match::name("reshape"); } |
There was a problem hiding this comment.
This should check there is only one argument: match::name("reshape")(match::nargs(1))
| // the wrong shape or fails in the copy itself. Reject it explicitly rather than | ||
| // lowering to something that silently computes the wrong result. | ||
| if(ins->inputs().size() == 2) | ||
| MIGRAPHX_THROW("lower_reshape: reshape with a runtime output buffer (2 input form) is " |
There was a problem hiding this comment.
Dont throw an error for this case. We could add a later pass to handle it.
| auto expected = ins->get_shape().to_symbolic(); | ||
| auto output_dims = ins->get_shape().sym_dims(); | ||
| auto reshaped = reshape_dims(s.to_symbolic(), output_dims, {.lazy = true}); | ||
| if(reshaped and *reshaped == expected) |
There was a problem hiding this comment.
This should use same_symbol with number elements:
| if(reshaped and *reshaped == expected) | |
| if(reshaped and same_symbol(reshaped->sym_elements(), expected.sym_elements()) |
|
|
||
| auto result = std::prev(m.end())->inputs().front(); | ||
| EXPECT(result->name() == "reshape_lazy"); | ||
| EXPECT(result->inputs().front()->name() == "gpu::contiguous"); |
There was a problem hiding this comment.
Tests should build the expected module.
| namespace gpu { | ||
|
|
||
| namespace { | ||
| instruction_ref insert_copy(module& m, |
There was a problem hiding this comment.
This should be named insert_precompile_op.
| instruction_ref pos, | ||
| instruction_ref input, | ||
| const operation& op, | ||
| const shape& output_shape) |
There was a problem hiding this comment.
Remove this parameter, this can be computed from the op and input.
| pos, make_op("gpu::precompile_op", {{"op", to_value(op)}}), input, alloc); | ||
| } | ||
|
|
||
| instruction_ref insert_standard_copy(module& m, instruction_ref pos, instruction_ref input) |
There was a problem hiding this comment.
This should be named insert_contiguous.
| auto layout_op = make_op("layout", {{"permutation", perm}}); | ||
| auto layout_shape = layout_op.compute_shape({s}); | ||
| auto layout_reshape = reshape_dims(layout_shape, output_dims, {.lazy = true}); | ||
| if(layout_reshape and *layout_reshape == expected) |
There was a problem hiding this comment.
This should be removed. The reshape_dims or reshape_lazy should not fail here.
| auto layout_op = make_op("layout", {{"permutation", perm}}); | |
| auto layout_shape = layout_op.compute_shape({s}); | |
| auto layout_reshape = reshape_dims(layout_shape, output_dims, {.lazy = true}); | |
| if(layout_reshape and *layout_reshape == expected) |
|
I would like @shivadbhavsar to review this as well to make sure the symbolic things are correct. |
|
Comments will be addressed by wensday |
Motivation
reshapelowering is currently split across three passes:lowering(add_reshape_lazy_op) expands everyreshapetogpu::contiguous -> reshape_lazy -> gpu::contiguous, unconditionally.eliminate_contiguousdeletes the redundant copies.propagate_reshape_layoutrewrites any surviving standardizing contiguous into alayoutto recover the discarded permutation.Step 1 runs before
eliminate_contiguous, so it cannot know the reshape's final inputlayout. Steps 2 and 3 exist to undo its guess.
Technical Details
Defer lowering until after
eliminate_contiguousand do it in one pass.add_reshape_lazy_opfromlowering.cpp;reshapepasses through untouched.propagate_reshape_layout(pass, header, test).lower_reshapein the same pipeline slot (target.cpp: aftereliminate_contiguous+dead_code_elimination, beforeadjust_allocation).Per
reshape, in order:reshape_dims(input, output_dims, {.lazy = true})succeeds and== expectedshape ->emit
reshape_lazyonly. Equality is required becausereshape_dimscan succeed withdifferent strides than
op::reshape::compute_shapeproduced.reshape_dims(output, input_dims, {.lazy = true})->find_permutation->layout; verify forward thatreshape_dims(layout_shape, output_dims, {.lazy = true}) == expected. Emitslayoutundergpu::precompile_op(one pointwise copy kernel viapointwise_compiler) +reshape_lazy. Forward check is required; the backwardsderivation is ambiguous for singleton dims.
gpu::contiguous+reshape_lazy.The trailing
gpu::contiguousis gone, so the result is no longer forced to standard;non-standard views now propagate further downstream than they did before.
Two-input
reshapenow throws. It lowered togpu::contiguous(data, out_buffer), butgpu::contiguous::compute_shapeusesinputs().at(0)only, soreshape(x{2,3,4}, out{6,4})reported{2,3,4}- andreplace_instructionalwaysrecomputes shape, so it is not overridable. No GPU copy op expresses a rank-changing copy;
all derive the kernel from one index space shared by src and dst, including
hip::copy(
"Ranks must be the same"dynamic,reorder_dims' rank assert static). Not a regression:developalso fails here via a 3-arggpu::contiguoustrippingcheck_shapes.has(2).simplify_dyn_opsalready folds compile-time-knowable targets into the one-input form.Changelog Category
Add a
CHANGELOG.mdentry for any option other thanNot Applicable