[Bug]: [GPU] StridedSlice/Slice with non-constant strides is skipped as identity when the output shape equals the input shape (e.g. reversal with step -1)
OpenVINO Version
2026.4.0-22959-99c81491cc3-releases/2026/4 (pip wheel); the code path is unchanged on master (checked 2026-09-18).
Operating System
Windows System
Device used for inference
GPU
Framework
None
Model used
Minimal ov.Model built from opset13, see reproducer.
Issue description
A Slice-8 (lowered by the GPU plugin to its strided_slice primitive) whose start/stop/step come from runtime inputs returns the input unchanged whenever the sliced output has the same shape as the input, e.g. a full reversal with step = -1. CPU is correct. Cases whose output shape differs (step = -2, partial ranges such as 3:0:-1) are correct on GPU, and the same slice with a constant step = -1 is also correct on GPU.
Root cause, as far as I can tell: mark_runtime_skippable_nodes marks a strided_slice node as runtime-skippable based on prim->begin / prim->strides / prim->end (src/plugins/intel_gpu/src/graph/graph_optimizer/mark_runtime_skippable_nodes.cpp, the do_for_types<strided_slice> block). When those inputs are not constants the vectors are empty, so all_zeroes(begin), all_ones(strides) (both std::all_of → vacuously true on an empty vector) and the !end.empty() && !is_valid guard all pass, and the node is marked skippable. At execution primitive_inst::do_runtime_skip_strided_slice only compares the input and output layouts, which are equal for a reversal, so the node is optimized out and the data is passed through un-reversed. A runtime strides input cannot be assumed to be all ones, so the node should not be marked skippable (at least) when prim->strides is empty.
The runtime graph confirms the lowering: Slice_7 | StridedSlice | impl: strided_slice_ref__i32.
I hit this while adding PyTorch frontend coverage for aten::slice with a runtime negative step (#38136).
Step-by-step reproduction
import numpy as np, openvino as ov
from openvino import opset13 as ops
data = ops.parameter([-1], np.int32)
start = ops.parameter([1], np.int32); stop = ops.parameter([1], np.int32); step = ops.parameter([1], np.int32)
m = ov.Model([ops.slice(data, start, stop, step, ops.constant(np.array([0], np.int32)))], [data, start, stop, step])
d = np.array([10, 20, 30, 40, 50], np.int32)
INT_MIN, INT_MAX = -2**31, 2**31 - 1
cases = [(-1, INT_MIN, -1), (4, -6, -1), (-1, INT_MIN, -2), (3, 0, -1), (0, INT_MAX, 1)]
for dev in ("CPU", "GPU"):
c = ov.Core().compile_model(m, dev)
for s, e, st in cases:
out = c([d, np.array([s], np.int32), np.array([e], np.int32), np.array([st], np.int32)])[0]
print(f"{dev} start={s:>11} stop={e:>11} step={st:>2} -> {out.tolist()}")Output:
CPU start= -1 stop=-2147483648 step=-1 -> [50, 40, 30, 20, 10]
CPU start= 4 stop= -6 step=-1 -> [50, 40, 30, 20, 10]
CPU start= -1 stop=-2147483648 step=-2 -> [50, 30, 10]
CPU start= 3 stop= 0 step=-1 -> [40, 30, 20]
CPU start= 0 stop= 2147483647 step= 1 -> [10, 20, 30, 40, 50]
GPU start= -1 stop=-2147483648 step=-1 -> [10, 20, 30, 40, 50] <-- wrong, not reversed
GPU start= 4 stop= -6 step=-1 -> [10, 20, 30, 40, 50] <-- wrong, not reversed
GPU start= -1 stop=-2147483648 step=-2 -> [50, 30, 10]
GPU start= 3 stop= 0 step=-1 -> [40, 30, 20]
GPU start= 0 stop= 2147483647 step= 1 -> [10, 20, 30, 40, 50]Expected: the GPU results match CPU / Python slicing semantics (d[-1::-1] is [50, 40, 30, 20, 10]).
Reproduced on an integrated GPU exposed through OpenCL (gfx90c), but the faulty decision is host-side in the graph optimizer, so it should not depend on the GPU model.
Relevant log output
(no error; the result is silently wrong)Issue submission checklist
- I'm reporting an issue. It's not a question.
- I checked the problem with the documentation, FAQ, open issues, Stack Overflow, etc., and have not found a solution.
- There is reproducer code and related data files such as images, videos, models, etc.
Source: openvinotoolkit/openvino