blob: e39e4afcecee27885c47d37cffc72a6b677aa8d2 [file] [log] [blame]
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
Teresa Charlin86b03572023-04-28 13:19:12 +01005
6#pragma once
7
8#include <OpaqueDelegateUtils.hpp>
Mike Kelly04f71202023-05-05 15:35:18 +01009#include <fmt/format.h>
Teresa Charlin86b03572023-04-28 13:19:12 +010010
11namespace armnnOpaqueDelegate
12{
13
14TfLiteStatus VisitSliceOperator(DelegateData& delegateData,
15 TfLiteOpaqueContext* tfLiteContext,
16 TfLiteOpaqueNode* tfLiteNode,
17 int nodeIndex,
18 int32_t tfLiteSliceOperatorCode)
19{
20
21 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 3, nodeIndex));
22 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
23
24 // Read inputs [input, begin, size]
25 // Gather input indices and use to get input tensor.
26 const int* inputTensors;
27 int numInputs;
28 if (TfLiteOpaqueNodeInputs(tfLiteNode, &inputTensors, &numInputs) != kTfLiteOk)
29 {
30 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
31 tfLiteContext,
32 "TfLiteArmnnOpaqueDelegate: Unable to gather input tensor indices from node #%d: ",
33 nodeIndex);
34 return kTfLiteError;
35 }
36
37 std::vector<const TfLiteOpaqueTensor*> tfLiteInputTensors;
38 tfLiteInputTensors.reserve(numInputs);
39 for (int i = 0; i < numInputs; i++)
40 {
41 const TfLiteOpaqueTensor* inputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputTensors[i]);
42 tfLiteInputTensors.push_back(inputTensor);
43 if (!IsValid(tfLiteContext, inputTensor, tfLiteSliceOperatorCode, nodeIndex))
44 {
45 return kTfLiteError;
46 }
47 }
48
49 const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteInputTensors[0]);
50
51 // We save the begin and size tensors in our descriptor. Therefore we have to read those values from inputs
52 unsigned int inputRank = inputTensorInfo.GetNumDimensions();
Mike Kelly04f71202023-05-05 15:35:18 +010053 auto ReadInt32Input = [&](int inputIndex, std::vector<int32_t>& outputData, const char* name) -> TfLiteStatus
Teresa Charlin86b03572023-04-28 13:19:12 +010054 {
55 if (TfLiteOpaqueTensorType(tfLiteInputTensors[inputIndex]) != kTfLiteInt32)
56 {
57 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
58 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010059 "TfLiteArmnnOpaqueDelegate: The %s Tensor of the Slice operation needs to "
Teresa Charlin86b03572023-04-28 13:19:12 +010060 "be of type int32. Operator: #%d node #%d: ",
Mike Kelly04f71202023-05-05 15:35:18 +010061 name, tfLiteSliceOperatorCode, nodeIndex);
Teresa Charlin86b03572023-04-28 13:19:12 +010062 return kTfLiteError;
63 }
64 uint32_t rank = TfLiteOpaqueTensorNumDims(tfLiteInputTensors[inputIndex]);
65 if (rank != 1)
66 {
67 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
68 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010069 "TfLiteArmnnOpaqueDelegate: The %s Tensor of the Slice operation needs to "
Teresa Charlin86b03572023-04-28 13:19:12 +010070 "be a 1D-Tensor. Operator: #%d node #%d: ",
Mike Kelly04f71202023-05-05 15:35:18 +010071 name, tfLiteSliceOperatorCode, nodeIndex);
Teresa Charlin86b03572023-04-28 13:19:12 +010072 return kTfLiteError;
73 }
74 uint32_t numValues = TfLiteOpaqueTensorDim(tfLiteInputTensors[inputIndex], 0);
75 if (numValues != inputRank)
76 {
77 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
78 tfLiteContext,
Mike Kelly04f71202023-05-05 15:35:18 +010079 "TfLiteArmnnOpaqueDelegate: The number of values in the %s Tensor of the "
80 "Slice operation needs to be equal to the rank of the Input Tensor. Operator: #%d node #%d: ",
81 name, tfLiteSliceOperatorCode, nodeIndex);
Teresa Charlin86b03572023-04-28 13:19:12 +010082 return kTfLiteError;
83 }
84 // return tensor data
Mike Kelly04f71202023-05-05 15:35:18 +010085 auto* tensorDataPtr = static_cast<int32_t*>(TfLiteOpaqueTensorData(tfLiteInputTensors[inputIndex]));
Teresa Charlin86b03572023-04-28 13:19:12 +010086 outputData.assign(tensorDataPtr, tensorDataPtr + numValues);
87 return kTfLiteOk;
88 };
89
Mike Kelly04f71202023-05-05 15:35:18 +010090 std::vector<int32_t> signedBegin;
91 if (ReadInt32Input(1, signedBegin, "Begin") != kTfLiteOk)
92 {
Teresa Charlin86b03572023-04-28 13:19:12 +010093 return kTfLiteError;
Mike Kelly04f71202023-05-05 15:35:18 +010094 }
95
96 std::vector<int32_t> signedSize;
97 if (ReadInt32Input(2, signedSize, "Size") != kTfLiteOk)
98 {
Teresa Charlin86b03572023-04-28 13:19:12 +010099 return kTfLiteError;
Mike Kelly04f71202023-05-05 15:35:18 +0100100 }
101
102 std::vector<uint32_t> begin({ signedBegin.begin(), signedBegin.end() });
103 std::vector<uint32_t> size(signedSize.size());
104
105 for (unsigned int i = 0; i < signedSize.size(); ++i)
106 {
107 int signedValue = signedSize[i];
108 if (signedValue < -1 || signedValue > TfLiteOpaqueTensorDim(tfLiteInputTensors[0], i) - signedBegin[i])
109 {
110 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
111 tfLiteContext,
112 "TfLiteArmnnDelegate: Invalid value for Size. Size must be in range [-1, inputDimSize - begin] "
113 "[-1, %d] inclusive but was %d Operator: #%d node #%d: ",
114 TfLiteOpaqueTensorDim(tfLiteInputTensors[0], i) - signedBegin[i], signedValue,
115 tfLiteSliceOperatorCode, nodeIndex);
116 return kTfLiteError;
117 }
118 if (signedValue == -1)
119 {
120 size[i] = TfLiteOpaqueTensorDim(tfLiteInputTensors[0], i) - signedBegin[i];
121 }
122 else
123 {
124 size[i] = static_cast<uint32_t>(signedValue);
125 }
126 }
Teresa Charlin86b03572023-04-28 13:19:12 +0100127
128 // Write all data to the descriptor
129 armnn::SliceDescriptor descriptor(begin, size);
130
131 // Validate output
132 // Gather output indices and use to get output tensor.
133 const int* outputTensors;
134 int numOutputs;
135 if (TfLiteOpaqueNodeOutputs(tfLiteNode, &outputTensors, &numOutputs) != kTfLiteOk)
136 {
137 TF_LITE_OPAQUE_MAYBE_KERNEL_LOG(
138 tfLiteContext,
139 "TfLiteArmnnOpaqueDelegate: Unable to gather output tensor indices from node #%d: ",
140 nodeIndex);
141 return kTfLiteError;
142 }
143
144 const TfLiteOpaqueTensor* tfLiteOutputTensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputTensors[0]);
145 if (!IsValid(tfLiteContext, tfLiteOutputTensor, tfLiteSliceOperatorCode, nodeIndex))
146 {
147 return kTfLiteError;
148 }
149
150 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tfLiteOutputTensor, true);
151
152 bool isSupported = false;
153 armnn::BackendId setBackend;
154 auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported)
155 {
156 FORWARD_LAYER_OPAQUE_SUPPORT_FUNC("SLICE",
157 tfLiteContext,
158 IsSliceSupported,
159 delegateData.m_Backends,
160 isSupported,
161 setBackend,
162 inputTensorInfo,
163 outInfo,
164 descriptor);
165 };
166
167 if (!delegateData.m_Network)
168 {
169 validateFunc(outputTensorInfo, isSupported);
170 return isSupported ? kTfLiteOk : kTfLiteError;
171 }
Mike Kelly04f71202023-05-05 15:35:18 +0100172 auto layerName = fmt::format("Slice:{}", nodeIndex);
Teresa Charlin86b03572023-04-28 13:19:12 +0100173
174 // Add a Slice layer
Mike Kelly04f71202023-05-05 15:35:18 +0100175 armnn::IConnectableLayer* layer = delegateData.m_Network->AddSliceLayer(descriptor, layerName.c_str());
Teresa Charlin86b03572023-04-28 13:19:12 +0100176 layer->SetBackendId(setBackend);
177 ARMNN_ASSERT(layer != nullptr);
178
179 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
180 outputSlot.SetTensorInfo(outputTensorInfo);
181
182 // try to connect the Constant Inputs if there are any
183 if(ProcessInputs(layer,delegateData, tfLiteContext, tfLiteNode) != kTfLiteOk )
184 {
185 return kTfLiteError;
186 }
187
188 // Connect
189 return Connect(layer, tfLiteContext, tfLiteNode, delegateData);
190}
191
192} // namespace armnnOpaqueDelegate
193