Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions runtime/compute/cker/include/cker/Shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,18 @@ inline int Offset(const Shape &shape, int i0, int i1, int i2, int i3)
return ((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3;
}

inline int Offset(const Shape &shape, int i0, int i1, int i2, int i3, int i4)
{
assert(shape.DimensionsCount() == 5);
const int *dim = shape.DimsDataUpTo6D();
assert(i0 >= 0 && i0 < dim[0]);
assert(i1 >= 0 && i1 < dim[1]);
assert(i2 >= 0 && i2 < dim[2]);
assert(i3 >= 0 && i3 < dim[3]);
assert(i4 >= 0 && i4 < dim[4]);
return ((((i0 * dim[1] + i1) * dim[2] + i2) * dim[3] + i3) * dim[4]) + i4;
}

inline int Offset(const Shape &shape, int i0, int i1, int i2, int i3, int i4, int i5)
{
assert(shape.DimensionsCount() == 6);
Expand Down
6 changes: 3 additions & 3 deletions runtime/compute/cker/include/cker/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,11 @@ struct SliceParams
struct StridedSliceParams
{
int8_t start_indices_count;
int16_t start_indices[4];
int32_t start_indices[5];
int8_t stop_indices_count;
int16_t stop_indices[4];
int32_t stop_indices[5];
int8_t strides_count;
int16_t strides[4];
int32_t strides[5];
Comment thread
ragmani marked this conversation as resolved.

int16_t begin_mask;
int16_t ellipsis_mask;
Expand Down
56 changes: 31 additions & 25 deletions runtime/compute/cker/include/cker/operation/StridedSlice.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ inline int Clamp(const int v, const int lo, const int hi)
inline void StridedSlicePadIndices(StridedSliceParams *p, int dim_count)
{
// Add indices and mask bits to fully include extra dimensions
assert(dim_count <= 4);
assert(dim_count <= 5);
assert(dim_count >= p->start_indices_count);
assert(p->start_indices_count == p->stop_indices_count);
assert(p->stop_indices_count == p->strides_count);
Expand Down Expand Up @@ -258,8 +258,8 @@ template <typename T>
inline void StridedSlice(const StridedSliceParams &op_params, const Shape &unextended_input_shape,
const T *input_data, const Shape &unextended_output_shape, T *output_data)
{
assert(unextended_input_shape.DimensionsCount() <= 4);
assert(unextended_output_shape.DimensionsCount() <= 4);
assert(unextended_input_shape.DimensionsCount() <= 5);
assert(unextended_output_shape.DimensionsCount() <= 5);

bool optimize = true;
int st_count = op_params.strides_count;
Expand Down Expand Up @@ -293,36 +293,42 @@ inline void StridedSlice(const StridedSliceParams &op_params, const Shape &unext
// Note that the output_shape is not used herein.
StridedSliceParams params_copy = op_params;

const Shape input_shape = Shape::ExtendedShape(4, unextended_input_shape);
const Shape output_shape = Shape::ExtendedShape(4, unextended_output_shape);
const Shape input_shape = Shape::ExtendedShape(5, unextended_input_shape);
const Shape output_shape = Shape::ExtendedShape(5, unextended_output_shape);

// Reverse and pad to 4 dimensions because that is what the runtime code
// requires (ie. all shapes must be 4D and are given backwards).
StridedSlicePadIndices(&params_copy, 4);
// Reverse and pad to 5 dimensions because that is what the runtime code
// requires (ie. all shapes must be 5D and are given backwards).
StridedSlicePadIndices(&params_copy, 5);

const int start_b = StartForAxis(params_copy, input_shape, 0);
const int stop_b = StopForAxis(params_copy, input_shape, 0, start_b);
const int start_h = StartForAxis(params_copy, input_shape, 1);
const int stop_h = StopForAxis(params_copy, input_shape, 1, start_h);
const int start_w = StartForAxis(params_copy, input_shape, 2);
const int stop_w = StopForAxis(params_copy, input_shape, 2, start_w);
const int start_d = StartForAxis(params_copy, input_shape, 3);
const int stop_d = StopForAxis(params_copy, input_shape, 3, start_d);
const int start_0 = StartForAxis(params_copy, input_shape, 0);
const int stop_0 = StopForAxis(params_copy, input_shape, 0, start_0);
const int start_1 = StartForAxis(params_copy, input_shape, 1);
const int stop_1 = StopForAxis(params_copy, input_shape, 1, start_1);
const int start_2 = StartForAxis(params_copy, input_shape, 2);
const int stop_2 = StopForAxis(params_copy, input_shape, 2, start_2);
const int start_3 = StartForAxis(params_copy, input_shape, 3);
const int stop_3 = StopForAxis(params_copy, input_shape, 3, start_3);
const int start_4 = StartForAxis(params_copy, input_shape, 4);
const int stop_4 = StopForAxis(params_copy, input_shape, 4, start_4);

T *out_ptr = output_data;
for (int in_b = start_b; !LoopCondition(in_b, stop_b, params_copy.strides[0]);
in_b += params_copy.strides[0])
for (int in_0 = start_0; !LoopCondition(in_0, stop_0, params_copy.strides[0]);
in_0 += params_copy.strides[0])
{
for (int in_h = start_h; !LoopCondition(in_h, stop_h, params_copy.strides[1]);
in_h += params_copy.strides[1])
for (int in_1 = start_1; !LoopCondition(in_1, stop_1, params_copy.strides[1]);
in_1 += params_copy.strides[1])
{
for (int in_w = start_w; !LoopCondition(in_w, stop_w, params_copy.strides[2]);
in_w += params_copy.strides[2])
for (int in_2 = start_2; !LoopCondition(in_2, stop_2, params_copy.strides[2]);
in_2 += params_copy.strides[2])
{
for (int in_d = start_d; !LoopCondition(in_d, stop_d, params_copy.strides[3]);
in_d += params_copy.strides[3])
for (int in_3 = start_3; !LoopCondition(in_3, stop_3, params_copy.strides[3]);
in_3 += params_copy.strides[3])
{
*out_ptr++ = input_data[Offset(input_shape, in_b, in_h, in_w, in_d)];
for (int in_4 = start_4; !LoopCondition(in_4, stop_4, params_copy.strides[4]);
in_4 += params_copy.strides[4])
{
*out_ptr++ = input_data[Offset(input_shape, in_0, in_1, in_2, in_3, in_4)];
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions runtime/compute/cker/src/Shape.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,18 @@ TEST(ShapeTest, neg_Offset4DNegativeIndex)
".*");
}

// Test that calling Offset on a 5D shape with a negative index triggers an assertion.
TEST(ShapeTest, neg_Offset5DNegativeIndex)
{
Shape s{2, 3, 4, 5, 6};
EXPECT_EXIT_BY_ABRT_DEBUG_ONLY(
{
int offset = Offset(s, 1, 1, -1, 1, 1);
(void)offset;
},
".*");
}

// Test that calling Offset on a 6D shape with an out-of-range index triggers an assertion.
TEST(ShapeTest, neg_Offset6DIndexOutOfRange)
{
Expand Down
87 changes: 87 additions & 0 deletions runtime/compute/cker/src/StridedSlice.test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <cker/operation/StridedSlice.h>
#include <cker/Types.h>

#include <gtest/gtest.h>
#include <vector>

#include "DeathTestMacro.h"

TEST(CKer_Operation, StridedSlice5D)
{
nnfw::cker::StridedSliceParams op_params{};
op_params.start_indices_count = 5;
op_params.stop_indices_count = 5;
op_params.strides_count = 5;

op_params.stop_indices[0] = 1;
op_params.stop_indices[1] = 1;
op_params.stop_indices[2] = 2;
op_params.stop_indices[3] = 2;
op_params.stop_indices[4] = 2;

op_params.strides[0] = 1;
op_params.strides[1] = 1;
op_params.strides[2] = 1;
op_params.strides[3] = 1;
op_params.strides[4] = 1;

nnfw::cker::Shape input_shape{2, 1, 2, 2, 2};
std::vector<float> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

nnfw::cker::Shape output_shape{1, 1, 2, 2, 2};
std::vector<float> output(output_shape.FlatSize());

nnfw::cker::StridedSlice(op_params, input_shape, input.data(), output_shape, output.data());

std::vector<float> expected_output = {0, 1, 2, 3, 4, 5, 6, 7};
for (size_t i = 0; i < expected_output.size(); ++i)
EXPECT_NEAR(output[i], expected_output[i], 1e-5f);
}

TEST(CKer_Operation, neg_StridedSliceNotSupportedDims)
{
nnfw::cker::StridedSliceParams op_params{};
op_params.start_indices_count = 5;
op_params.stop_indices_count = 5;
op_params.strides_count = 5;

op_params.stop_indices[0] = 1;
op_params.stop_indices[1] = 1;
op_params.stop_indices[2] = 2;
op_params.stop_indices[3] = 2;
op_params.stop_indices[4] = 2;

op_params.strides[0] = 1;
op_params.strides[1] = 1;
op_params.strides[2] = 1;
op_params.strides[3] = 1;
op_params.strides[4] = 1;

nnfw::cker::Shape input_shape{2, 1, 2, 2, 2, 1};
std::vector<float> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

nnfw::cker::Shape output_shape{1, 1, 2, 2, 2, 1};
std::vector<float> output(output_shape.FlatSize());

EXPECT_EXIT_BY_ABRT_DEBUG_ONLY(
{
nnfw::cker::StridedSlice(op_params, input_shape, input.data(), output_shape, output.data());
},
".*");
}
6 changes: 3 additions & 3 deletions runtime/onert/core/include/util/ShapeInference.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ ir::Shape inferSqueezeShape(const ir::Shape &in_shape, const ir::operation::Sque
struct StridedSliceParams
{
int8_t start_indices_count;
int16_t start_indices[4];
int32_t start_indices[5];
int8_t stop_indices_count;
int16_t stop_indices[4];
int32_t stop_indices[5];
int8_t strides_count;
int16_t strides[4];
int32_t strides[5];

int16_t begin_mask;
int16_t ellipsis_mask;
Expand Down
2 changes: 1 addition & 1 deletion runtime/onert/core/src/compiler/ShapeValidator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ void ShapeValidator::visit(const ir::operation::StridedSlice &node)
if (operands.at(output_index).info().isDynamic())
return;

OP_REQUIRES(operands.at(input_index).shape().rank() <= 4);
OP_REQUIRES(operands.at(input_index).shape().rank() <= 5);
}

void ShapeValidator::visit(const ir::operation::Split &node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,57 @@ TEST_F(GenModelTest, OneOp_StridedSlice_LastDim)
SUCCEED();
}

TEST_F(GenModelTest, OneOp_StridedSlice_5D)
{
CircleGen cgen;
std::vector<int32_t> begin_data{0, 0, 0, 0, 0};
std::vector<int32_t> end_data{1, 1, 2, 2, 2};
std::vector<int32_t> strides_data{1, 1, 1, 1, 1};
uint32_t begin_buf = cgen.addBuffer(begin_data);
uint32_t end_buf = cgen.addBuffer(end_data);
uint32_t strides_buf = cgen.addBuffer(strides_data);
int input = cgen.addTensor({{2, 1, 2, 2, 2}, circle::TensorType::TensorType_FLOAT32});
int begin = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, begin_buf});
int end = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, end_buf});
int strides = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, strides_buf});
int out = cgen.addTensor({{1, 1, 2, 2, 2}, circle::TensorType::TensorType_FLOAT32});
cgen.addOperatorStridedSlice({{input, begin, end, strides}, {out}}, 0, 0);
cgen.setInputsAndOutputs({input}, {out});

_context = std::make_unique<GenModelTestContext>(cgen.finish());
_context->addTestCase(uniformTCD<float>({{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
{{0, 1, 2, 3, 4, 5, 6, 7}}));
_context->setBackends({"acl_cl", "acl_neon", "cpu"});

SUCCEED();
}

TEST_F(GenModelTest, neg_OneOp_StridedSlice_UnsupportedDims)
{
CircleGen cgen;
std::vector<int32_t> begin_data{0, 0, 0, 0, 0};
std::vector<int32_t> end_data{1, 1, 2, 2, 2};
std::vector<int32_t> strides_data{1, 1, 1, 1, 1};
uint32_t begin_buf = cgen.addBuffer(begin_data);
uint32_t end_buf = cgen.addBuffer(end_data);
uint32_t strides_buf = cgen.addBuffer(strides_data);
int input = cgen.addTensor({{2, 1, 2, 2, 2, 1}, circle::TensorType::TensorType_FLOAT32});
int begin = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, begin_buf});
int end = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, end_buf});
int strides = cgen.addTensor({{5}, circle::TensorType::TensorType_INT32, strides_buf});
int out = cgen.addTensor({{1, 1, 2, 2, 2, 1}, circle::TensorType::TensorType_FLOAT32});
cgen.addOperatorStridedSlice({{input, begin, end, strides}, {out}}, 0, 0);
cgen.setInputsAndOutputs({input}, {out});

_context = std::make_unique<GenModelTestContext>(cgen.finish());
_context->addTestCase(uniformTCD<float>({{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
{{0, 1, 2, 3, 4, 5, 6, 7}}));
_context->setBackends({"acl_cl", "acl_neon", "cpu"});
_context->expectFailCompile();

SUCCEED();
}

TEST_F(GenModelTest, neg_OneOp_StridedSlice_DifferentType)
{
CircleGen cgen;
Expand Down