diff --git a/src/plugins/intel_gpu/src/graph/include/reshape_inst.h b/src/plugins/intel_gpu/src/graph/include/reshape_inst.h index bb2e5978ea903e..69e773802dc982 100644 --- a/src/plugins/intel_gpu/src/graph/include/reshape_inst.h +++ b/src/plugins/intel_gpu/src/graph/include/reshape_inst.h @@ -100,14 +100,21 @@ struct typed_program_node : public typed_program_node_base { // Iteratively check the total product of all static innermost dimensions // until the crop dimension value matches or the first dynamic dimension is encountered int64_t mul = 1; + size_t matched_trailing_dims = 0; for (size_t i = output_pshape.size(); i > 1 ; i--) { if (output_pshape[i - 1].is_dynamic() || mul == input_last_dim_val) break; mul *= output_pshape[i - 1].get_length(); + matched_trailing_dims++; } if (input_last_dim_val != mul) return false; + // Reject when reshape drops the cropped axis (e.g. [N,M,1] -> [N,M]): no output axis can + // carry the cropped axis padding, so sibling crop outputs would all point to the same + // base buffer region (aliased). + if (matched_trailing_dims == 0 && output_pshape.size() < input_pshape.size()) + return false; return true; } diff --git a/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp b/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp index d6305ab951c04b..5fcb907665dcb1 100644 --- a/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp +++ b/src/plugins/intel_gpu/tests/unit/passes/prepare_buffer_fusing_test.cpp @@ -2095,3 +2095,45 @@ TEST(prepare_buffer_fusing, in_place_crop_self_multiply_spatial_split) { } } } + +// A base-mode reshape that drops the cropped (size-1) last axis must not be marked +// runtime-padding-propagatable; otherwise sibling crop outputs alias the same buffer. +TEST(prepare_buffer_fusing, in_place_crop_dynamic_last_axis_split_to_collapsing_reshape) { + auto& engine = get_test_engine(); + + auto in_layout = layout{ ov::PartialShape{-1, -1, 4}, data_types::f32, format::bfyx }; + auto axis_mem = engine.allocate_memory({ {}, data_types::i64, format::bfyx }); + auto splits_length_mem = engine.allocate_memory({ {4}, data_types::i64, format::bfyx }); + + const int64_t axis = 2; + set_values(axis_mem, { axis }); + set_values(splits_length_mem, { 1, 1, 1, 1 }); + + auto op_mode = cldnn::crop_ngraph_op_mode::variadic_split; + topology topology( + input_layout("input", in_layout), + data("axis", axis_mem), + data("splits_length", splits_length_mem), + crop("crop0", { input_info("input"), input_info("axis"), input_info("splits_length") }, + cldnn::tensor(1), cldnn::tensor(0), op_mode, 0, axis), + crop("crop1", { input_info("input"), input_info("axis"), input_info("splits_length") }, + cldnn::tensor(1), cldnn::tensor(0), op_mode, 1, axis), + // Drops the cropped axis: [-1,-1,1] -> [-1,-1] => must be rejected. + reshape("rs0_collapse", input_info("crop0"), false, std::vector{-1, 3}, + ov::PartialShape{-1, -1}, cldnn::reshape::reshape_mode::base), + // Preserves the cropped axis: [-1,-1,1] -> [-1,-1,1] => still allowed. + reshape("rs1_keep", input_info("crop1"), true, std::vector{-1, -1, 1}, + ov::PartialShape{-1, -1, 1}, cldnn::reshape::reshape_mode::base), + reorder("out0", input_info("rs0_collapse"), format::bfyx, data_types::f32), + reorder("out1", input_info("rs1_keep"), format::bfyx, data_types::f32) + ); + + ExecutionConfig config = get_test_default_config(engine); + config.set_property(ov::intel_gpu::allow_new_shape_infer(true)); + config.set_property(ov::intel_gpu::optimize_data(true)); + auto prog = program::build_program(engine, topology, config, false, true); + ASSERT_NE(prog, nullptr); + + ASSERT_FALSE(prog->get_node("rs0_collapse").as().is_runtime_propagatable_padding()); + ASSERT_TRUE(prog->get_node("rs1_keep").as().is_runtime_propagatable_padding()); +}