From 05e46933afb3dec2f7c9a0f45e0cdca13d8c7ab5 Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Thu, 10 Sep 2026 13:58:40 -0700 Subject: [PATCH 1/3] Validate NCHWc reorder channel layout --- onnxruntime/contrib_ops/cpu/nchwc_ops.cc | 5 ++- .../test/contrib_ops/nchwc_ops_test.cc | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 onnxruntime/test/contrib_ops/nchwc_ops_test.cc diff --git a/onnxruntime/contrib_ops/cpu/nchwc_ops.cc b/onnxruntime/contrib_ops/cpu/nchwc_ops.cc index fa097bb166d10..a22193f11c48d 100644 --- a/onnxruntime/contrib_ops/cpu/nchwc_ops.cc +++ b/onnxruntime/contrib_ops/cpu/nchwc_ops.cc @@ -127,7 +127,10 @@ Status ReorderOutput::Compute(OpKernelContext* context) const { const auto& X_shape = X->Shape().GetDims(); const auto X_rank = X_shape.size(); ORT_ENFORCE(X_rank == 4); - ORT_ENFORCE(channels_ <= X_shape[1]); + const int64_t nchwc_block_size = static_cast(MlasNchwcGetBlockSize()); + ORT_ENFORCE(X_shape[1] % nchwc_block_size == 0 && + channels_ <= X_shape[1] && X_shape[1] - channels_ < nchwc_block_size, + "Input channels must match the NCHWc block-aligned channel count."); // Build the output shape in NCHW or NHWC order. TensorShapeVector Y_shape(X_rank); diff --git a/onnxruntime/test/contrib_ops/nchwc_ops_test.cc b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc new file mode 100644 index 0000000000000..35583528c3e36 --- /dev/null +++ b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gtest/gtest.h" + +#include "core/mlas/inc/mlas.h" +#include "test/providers/provider_test_utils.h" +#include "test/util/include/default_providers.h" + +namespace onnxruntime { +namespace test { + +TEST(NchwcOpsTest, ReorderOutputRejectsUnalignedInputChannels) { + const int64_t block_size = static_cast(MlasNchwcGetBlockSize()); + if (block_size <= 1) { + GTEST_SKIP() << "NCHWc blocking is not enabled on this platform."; + } + + const int64_t input_channels = block_size - 1; + OpTester test("ReorderOutput", 1, kMSNchwcDomain); + test.AddAttribute("channels", int64_t{1}); + test.AddAttribute("channels_last", int64_t{0}); + test.AddInput("X", {1, input_channels, 2, 2}, + std::vector(static_cast(input_channels) * 4, 0.0f)); + test.AddOutput("Y", {1, 1, 2, 2}, {0.0f, 0.0f, 0.0f, 0.0f}); + + test.Config(OpTester::ExpectResult::kExpectFailure, + "Input channels must match the NCHWc block-aligned channel count.") + .ConfigEp(DefaultCpuExecutionProvider()) + .RunWithConfig(); +} + +} // namespace test +} // namespace onnxruntime \ No newline at end of file From a0e0fd57889f3d5927de96227232863468731c6b Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Mon, 21 Sep 2026 21:36:51 +0000 Subject: [PATCH 2/3] Cover extra NCHWc channel block Add the aligned input case where ReorderOutput receives one complete channel block beyond the requested output channels. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../test/contrib_ops/nchwc_ops_test.cc | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/onnxruntime/test/contrib_ops/nchwc_ops_test.cc b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc index 35583528c3e36..0d3e17c8c9a18 100644 --- a/onnxruntime/test/contrib_ops/nchwc_ops_test.cc +++ b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc @@ -30,5 +30,26 @@ TEST(NchwcOpsTest, ReorderOutputRejectsUnalignedInputChannels) { .RunWithConfig(); } +TEST(NchwcOpsTest, ReorderOutputRejectsExtraChannelBlock) { + const int64_t block_size = static_cast(MlasNchwcGetBlockSize()); + if (block_size <= 1) { + GTEST_SKIP() << "NCHWc blocking is not enabled on this platform."; + } + + const int64_t input_channels = 2 * block_size; + OpTester test("ReorderOutput", 1, kMSNchwcDomain); + test.AddAttribute("channels", block_size); + test.AddAttribute("channels_last", int64_t{0}); + test.AddInput("X", {1, input_channels, 2, 2}, + std::vector(static_cast(input_channels) * 4, 0.0f)); + test.AddOutput("Y", {1, block_size, 2, 2}, + std::vector(static_cast(block_size) * 4, 0.0f)); + + test.Config(OpTester::ExpectResult::kExpectFailure, + "Input channels must match the NCHWc block-aligned channel count.") + .ConfigEp(DefaultCpuExecutionProvider()) + .RunWithConfig(); +} + } // namespace test } // namespace onnxruntime \ No newline at end of file From 51ab03f19d48fb43d33cfad8d08efd876e50492c Mon Sep 17 00:00:00 2001 From: Akshay Sonawane Date: Mon, 21 Sep 2026 22:29:17 +0000 Subject: [PATCH 3/3] Repair merged NCHWc tests Restore the anonymous namespace and the extra-channel-block test setup lost during the main merge, fixing the test translation unit compile errors across CI configurations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- onnxruntime/test/contrib_ops/nchwc_ops_test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/onnxruntime/test/contrib_ops/nchwc_ops_test.cc b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc index 9b96df96758d1..a24df9b74ea41 100644 --- a/onnxruntime/test/contrib_ops/nchwc_ops_test.cc +++ b/onnxruntime/test/contrib_ops/nchwc_ops_test.cc @@ -11,6 +11,7 @@ namespace onnxruntime { namespace test { +namespace { TEST(NchwcOpsTest, ReorderOutputRejectsUnalignedInputChannels) { const int64_t block_size = static_cast(MlasNchwcGetBlockSize()); @@ -57,6 +58,11 @@ void RunInvalidNchwcConvTest(const std::vector& input_shape, } TEST(NchwcOpsTest, ReorderOutputRejectsExtraChannelBlock) { + const int64_t block_size = static_cast(MlasNchwcGetBlockSize()); + if (block_size <= 1) { + GTEST_SKIP() << "NCHWc blocking is not enabled on this platform."; + } + const int64_t input_channels = 2 * block_size; OpTester test("ReorderOutput", 1, kMSNchwcDomain); test.AddAttribute("channels", block_size); @@ -70,6 +76,8 @@ TEST(NchwcOpsTest, ReorderOutputRejectsExtraChannelBlock) { "Input channels must match the NCHWc block-aligned channel count.") .ConfigEp(DefaultCpuExecutionProvider()) .RunWithConfig(); +} + } // namespace TEST(NchwcOpsTest, ConvRejectsUnalignedOutputChannels) {