diff --git a/backends/cpu/runtime/CPUBackend.cpp b/backends/cpu/runtime/CPUBackend.cpp index 963bf3e7f13..3ff1396c71d 100644 --- a/backends/cpu/runtime/CPUBackend.cpp +++ b/backends/cpu/runtime/CPUBackend.cpp @@ -183,15 +183,20 @@ class CPUExecution { InvalidArgument, "CPU static shape/dtype/layout/storage mismatch: %s", method_->graph.value(id).name.c_str()); - int64_t stride = 1; - for (size_t reverse = expected.sizes.size(); reverse > 0; --reverse) { - const size_t dim = reverse - 1; - ET_CHECK_OR_RETURN_ERROR( - tensor.dim_order()[dim] == dim && tensor.strides()[dim] == stride, - InvalidArgument, - "CPU binding must be contiguous: %s", - method_->graph.value(id).name.c_str()); - stride *= expected.sizes[dim]; + // Empty bindings carry no data, so their strides and dim order are + // meaningless (PyTorch does not canonicalize them); skip the contiguity + // check rather than rejecting valid empty tensors. + if (tensor.nbytes() != 0) { + int64_t stride = 1; + for (size_t reverse = expected.sizes.size(); reverse > 0; --reverse) { + const size_t dim = reverse - 1; + ET_CHECK_OR_RETURN_ERROR( + tensor.dim_order()[dim] == dim && tensor.strides()[dim] == stride, + InvalidArgument, + "CPU binding must be contiguous: %s", + method_->graph.value(id).name.c_str()); + stride *= expected.sizes[dim]; + } } } // EValue exposes the logical span, but no backing capacity or readable diff --git a/backends/cpu/test/test_runtime.py b/backends/cpu/test/test_runtime.py index b3d1df05982..4e821d76eec 100644 --- a/backends/cpu/test/test_runtime.py +++ b/backends/cpu/test/test_runtime.py @@ -95,6 +95,17 @@ def forward(self, x, mask): for output, expected in zip(actual, model(x, current), strict=True): torch.testing.assert_close(output, expected, rtol=0, atol=0) + def test_empty_tensors_execute(self): + class Add(torch.nn.Module): + def forward(self, x): + return x + 1 + + model = Add() + x = torch.empty(2, 0, 3) + with self._lower(model, (x,)) as runtime: + actual = runtime.forward((x,))[0] + torch.testing.assert_close(actual, model(x)) + def test_neg_view_copy_routes_to_neg(self): class NegView(torch.nn.Module): def forward(self, x):