blob: 8309a79d38d9ff5c6b296bd54e9aabadea8a902b [file] [log] [blame]
Sadik Armagan62483be2020-10-23 17:14:43 +01001//
Ryan OShea3ad2e142023-01-13 10:19:20 +00002// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan62483be2020-10-23 17:14:43 +01003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Matthew Sloyan11572322023-03-16 10:17:51 +00008#include <ClassicDelegateUtils.hpp>
Jim Flynn4b2f3472021-10-13 21:20:07 +01009#include "MultiLayerFacade.hpp"
10#include "SharedFunctions.hpp"
Sadik Armagan67e95f22020-10-29 16:14:54 +000011
Sadik Armagan62483be2020-10-23 17:14:43 +010012#include <tensorflow/lite/builtin_ops.h>
13#include <tensorflow/lite/c/builtin_op_data.h>
14#include <tensorflow/lite/c/common.h>
15#include <tensorflow/lite/minimal_logging.h>
Sadik Armagan05e9fd22020-11-17 12:01:47 +000016#include "tensorflow/lite/delegates/utils.h"
Sadik Armagan62483be2020-10-23 17:14:43 +010017
18namespace armnnDelegate
19{
20
Sadik Armagan67e95f22020-10-29 16:14:54 +000021TfLiteStatus ValidateAddOperator(DelegateData& delegateData,
22 TfLiteContext* tfLiteContext,
23 const armnn::TensorInfo& inputInfo1,
24 const armnn::TensorInfo& inputInfo2,
25 const armnn::TensorInfo& outputInfo)
26{
27 bool isSupported = false;
28 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
29 {
Mike Kelly3ec30772023-03-08 13:47:17 +000030 std::vector<armnn::TensorInfo> infos { inputInfo1, inputInfo2, outputInfo };
Sadik Armaganbfa767c2022-02-09 14:58:03 +000031 FORWARD_LAYER_SUPPORT_FUNC("ADD",
Sadik Armagan67e95f22020-10-29 16:14:54 +000032 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +000033 IsElementwiseBinarySupported,
Sadik Armagan67e95f22020-10-29 16:14:54 +000034 delegateData.m_Backends,
35 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +010036 armnn::BackendId(),
Sadik Armagan67e95f22020-10-29 16:14:54 +000037 inputInfo1,
38 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +000039 outputInfo,
40 armnn::BinaryOperation::Add);
Sadik Armagan67e95f22020-10-29 16:14:54 +000041 };
42
43 validateFunc(outputInfo, isSupported);
44 return isSupported ? kTfLiteOk : kTfLiteError;
45}
46
Jim Flynn4b2f3472021-10-13 21:20:07 +010047
Sadik Armagan21a94ff2020-11-09 08:38:30 +000048TfLiteStatus ValidateDivOperator(DelegateData& delegateData,
49 TfLiteContext* tfLiteContext,
50 const armnn::TensorInfo& inputInfo1,
51 const armnn::TensorInfo& inputInfo2,
52 const armnn::TensorInfo& outputInfo)
Sadik Armagan67e95f22020-10-29 16:14:54 +000053{
Sadik Armagan21a94ff2020-11-09 08:38:30 +000054 bool isSupported = false;
55 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
Sadik Armagan67e95f22020-10-29 16:14:54 +000056 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +000057 FORWARD_LAYER_SUPPORT_FUNC("DIV",
Sadik Armagan21a94ff2020-11-09 08:38:30 +000058 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +000059 IsElementwiseBinarySupported,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000060 delegateData.m_Backends,
61 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +010062 armnn::BackendId(),
Sadik Armagan21a94ff2020-11-09 08:38:30 +000063 inputInfo1,
64 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +000065 outputTensorInfo,
66 armnn::BinaryOperation::Div);
Sadik Armagan21a94ff2020-11-09 08:38:30 +000067 };
Sadik Armagan67e95f22020-10-29 16:14:54 +000068
Sadik Armagan21a94ff2020-11-09 08:38:30 +000069 validateFunc(outputInfo, isSupported);
70 return isSupported ? kTfLiteOk : kTfLiteError;
71}
72
Jim Flynn4b2f3472021-10-13 21:20:07 +010073TfLiteStatus ValidateFloorDivOperator(DelegateData& delegateData,
74 TfLiteContext* tfLiteContext,
75 const armnn::TensorInfo& inputInfo1,
76 const armnn::TensorInfo& inputInfo2,
77 const armnn::TensorInfo& outputInfo)
78{
79 // need first to validate that the div operator is supported
80 // then that the floor operator is supported
81 TfLiteStatus status = ValidateDivOperator(delegateData, tfLiteContext, inputInfo1, inputInfo2, outputInfo);
82 if (status != kTfLiteOk)
83 {
84 return status;
85 }
86 // if the inputs and output of the div are all Signed32 we don't need to add the floor operator afterward.
87 if (AreAllSigned32(inputInfo1, inputInfo2, outputInfo))
88 {
89 return status;
90 }
91 // in case broadcasting is being done from one of the inputs to the div
92 // choose the full sized input tensor to pass to the floor validation routine
93 armnn::TensorInfo floorInputInfo = inputInfo1;
94 if (inputInfo1.GetNumDimensions() < inputInfo2.GetNumDimensions())
95 {
96 floorInputInfo = inputInfo2;
97 }
98 status = ValidateFloorOperator(delegateData, tfLiteContext, floorInputInfo, outputInfo);
99 return status;
100}
101
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000102TfLiteStatus ValidateMaximumOperator(DelegateData& delegateData,
103 TfLiteContext* tfLiteContext,
104 const armnn::TensorInfo& inputInfo1,
105 const armnn::TensorInfo& inputInfo2,
106 const armnn::TensorInfo& outputInfo)
107{
108 bool isSupported = false;
109 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
110 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000111 FORWARD_LAYER_SUPPORT_FUNC("MAXIMUM",
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000112 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +0000113 IsElementwiseBinarySupported,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000114 delegateData.m_Backends,
115 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100116 armnn::BackendId(),
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000117 inputInfo1,
118 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +0000119 outputTensorInfo,
120 armnn::BinaryOperation::Maximum);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000121 };
122
123 validateFunc(outputInfo, isSupported);
124 return isSupported ? kTfLiteOk : kTfLiteError;
125}
126
127TfLiteStatus ValidateMinimumOperator(DelegateData& delegateData,
128 TfLiteContext* tfLiteContext,
129 const armnn::TensorInfo& inputInfo1,
130 const armnn::TensorInfo& inputInfo2,
131 const armnn::TensorInfo& outputInfo)
132{
133 bool isSupported = false;
134 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
135 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000136 FORWARD_LAYER_SUPPORT_FUNC("MINIMUM",
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000137 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +0000138 IsElementwiseBinarySupported,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000139 delegateData.m_Backends,
140 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100141 armnn::BackendId(),
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000142 inputInfo1,
143 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +0000144 outputTensorInfo,
145 armnn::BinaryOperation::Minimum);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000146 };
147
148 validateFunc(outputInfo, isSupported);
149 return isSupported ? kTfLiteOk : kTfLiteError;
150}
151
152TfLiteStatus ValidateMulOperator(DelegateData& delegateData,
153 TfLiteContext* tfLiteContext,
154 const armnn::TensorInfo& inputInfo1,
155 const armnn::TensorInfo& inputInfo2,
156 const armnn::TensorInfo& outputInfo)
157{
158 bool isSupported = false;
159 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
160 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000161 FORWARD_LAYER_SUPPORT_FUNC("MUL",
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000162 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +0000163 IsElementwiseBinarySupported,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000164 delegateData.m_Backends,
165 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100166 armnn::BackendId(),
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000167 inputInfo1,
168 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +0000169 outputTensorInfo,
170 armnn::BinaryOperation::Mul);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000171 };
172
173 validateFunc(outputInfo, isSupported);
174 return isSupported ? kTfLiteOk : kTfLiteError;
175}
176
John Mcloughlin0ec00872023-05-15 17:03:49 +0100177TfLiteStatus ValidatePowerOperator(DelegateData& delegateData,
178 TfLiteContext* tfLiteContext,
179 const armnn::TensorInfo& inputInfo1,
180 const armnn::TensorInfo& inputInfo2,
181 const armnn::TensorInfo& outputInfo)
182{
183 bool isSupported = false;
184 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
185 {
186 FORWARD_LAYER_SUPPORT_FUNC("POWER",
187 tfLiteContext,
188 IsElementwiseBinarySupported,
189 delegateData.m_Backends,
190 isSupported,
191 armnn::BackendId(),
192 inputInfo1,
193 inputInfo2,
194 outputTensorInfo,
195 armnn::BinaryOperation::Power);
196 };
197
198 validateFunc(outputInfo, isSupported);
199 return isSupported ? kTfLiteOk : kTfLiteError;
200}
201
202TfLiteStatus ValidateSquaredDifferenceOperator(DelegateData& delegateData,
203 TfLiteContext* tfLiteContext,
204 const armnn::TensorInfo& inputInfo1,
205 const armnn::TensorInfo& inputInfo2,
206 const armnn::TensorInfo& outputInfo)
207{
208 bool isSupported = false;
209 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
210 {
211 FORWARD_LAYER_SUPPORT_FUNC("SQUAREDDIFFERENCE",
212 tfLiteContext,
213 IsElementwiseBinarySupported,
214 delegateData.m_Backends,
215 isSupported,
216 armnn::BackendId(),
217 inputInfo1,
218 inputInfo2,
219 outputTensorInfo,
220 armnn::BinaryOperation::SqDiff);
221 };
222
223 validateFunc(outputInfo, isSupported);
224 return isSupported ? kTfLiteOk : kTfLiteError;
225}
226
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000227TfLiteStatus ValidateSubOperator(DelegateData& delegateData,
228 TfLiteContext* tfLiteContext,
229 const armnn::TensorInfo& inputInfo1,
230 const armnn::TensorInfo& inputInfo2,
231 const armnn::TensorInfo& outputInfo)
232{
233 bool isSupported = false;
234 auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported)
235 {
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000236 FORWARD_LAYER_SUPPORT_FUNC("SUB",
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000237 tfLiteContext,
Mike Kelly3ec30772023-03-08 13:47:17 +0000238 IsElementwiseBinarySupported,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000239 delegateData.m_Backends,
240 isSupported,
Cathal Corbett53837672022-09-01 11:34:37 +0100241 armnn::BackendId(),
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000242 inputInfo1,
243 inputInfo2,
Mike Kelly3ec30772023-03-08 13:47:17 +0000244 outputTensorInfo,
245 armnn::BinaryOperation::Sub);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000246 };
247
248 validateFunc(outputInfo, isSupported);
249 return isSupported ? kTfLiteOk : kTfLiteError;
Sadik Armagan67e95f22020-10-29 16:14:54 +0000250}
251
Jim Flynn4b2f3472021-10-13 21:20:07 +0100252std::pair<armnn::IConnectableLayer*, armnn::IConnectableLayer*> AddFloorDivLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100253 DelegateData& delegateData,
254 const armnn::TensorInfo& outputTensorInfo,
255 int nodeIndex)
Jim Flynn4b2f3472021-10-13 21:20:07 +0100256{
Mike Kelly07169c82023-08-02 13:23:09 +0100257 auto divName = GetLayerName(armnn::BinaryOperation::Div, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000258 armnn::IConnectableLayer* divisionLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100259 armnn::BinaryOperation::Div, divName.c_str());
Jim Flynn4b2f3472021-10-13 21:20:07 +0100260 // if the output of the div is Signed32 the Floor layer is not required
261 if (armnn::DataType::Signed32 == outputTensorInfo.GetDataType())
262 {
263 return std::make_pair(divisionLayer, divisionLayer);
264 }
265 armnn::IOutputSlot& outputSlot = divisionLayer->GetOutputSlot(0);
266 outputSlot.SetTensorInfo(outputTensorInfo);
Mike Kelly07169c82023-08-02 13:23:09 +0100267 auto floorName = GetLayerName(armnn::LayerType::Floor, nodeIndex);
268 armnn::IConnectableLayer* floorLayer = delegateData.m_Network->AddFloorLayer(floorName.c_str());
Jim Flynn4b2f3472021-10-13 21:20:07 +0100269 outputSlot.Connect(floorLayer->GetInputSlot(0));
270 return std::make_pair(divisionLayer, floorLayer);
271}
272
Sadik Armagan62483be2020-10-23 17:14:43 +0100273TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData,
274 TfLiteContext* tfLiteContext,
275 TfLiteNode* tfLiteNode,
276 int nodeIndex,
277 int32_t elementwiseBinaryOperatorCode)
278{
Sadik Armagan67e95f22020-10-29 16:14:54 +0000279 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
280 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
281
282 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
283 const TfLiteTensor& tfLiteInputTensor0 = tfLiteTensors[tfLiteNode->inputs->data[0]];
284 if (IsDynamicTensor(tfLiteInputTensor0))
285 {
286 TF_LITE_MAYBE_KERNEL_LOG(
287 tfLiteContext,
288 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
289 elementwiseBinaryOperatorCode, nodeIndex);
290 return kTfLiteError;
291 }
292
293 const TfLiteTensor& tfLiteInputTensor1 = tfLiteTensors[tfLiteNode->inputs->data[1]];
294 if (IsDynamicTensor(tfLiteInputTensor1))
295 {
296 TF_LITE_MAYBE_KERNEL_LOG(
297 tfLiteContext,
298 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
299 elementwiseBinaryOperatorCode, nodeIndex);
300 return kTfLiteError;
301 }
302
303 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
304 if (IsDynamicTensor(tfLiteOutputTensor))
305 {
306 TF_LITE_MAYBE_KERNEL_LOG(
307 tfLiteContext,
308 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
309 elementwiseBinaryOperatorCode, nodeIndex);
310 return kTfLiteError;
311 }
312
Sadik Armagan05e9fd22020-11-17 12:01:47 +0000313 armnn::TensorInfo inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor0);
314 armnn::TensorInfo inputTensorInfo1 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor1);
315
Sadik Armagan90a119b2022-08-05 16:12:49 +0100316 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000317
Ryan OSheaa544f0f2023-01-25 18:10:20 +0000318 // Check if we need to expand the dims of the input tensor infos.
319 // This is required for a few of the backends.
320 if(inputTensorInfo0.GetNumDimensions() != inputTensorInfo1.GetNumDimensions())
321 {
322 ExpandTensorRankToEqual(inputTensorInfo0, inputTensorInfo1);
323 }
324
Ryan OShea3ad2e142023-01-13 10:19:20 +0000325 auto* tfLiteNodeParameters = reinterpret_cast<TfLiteAddParams*>(tfLiteNode->builtin_data);
Ryan OShea475c7a82023-01-30 14:24:15 +0000326 TfLiteFusedActivation activationType = kTfLiteActNone;
Ryan OShea3ad2e142023-01-13 10:19:20 +0000327 if (tfLiteNodeParameters)
328 {
329 activationType = tfLiteNodeParameters->activation;
Ryan OShea3ad2e142023-01-13 10:19:20 +0000330 TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo,
331 outputTensorInfo, activationType);
332 if(activationStatus != kTfLiteOk)
333 {
334 return kTfLiteError;
335 }
336 }
337
Sadik Armagan67e95f22020-10-29 16:14:54 +0000338 if (!delegateData.m_Network)
339 {
340 switch(elementwiseBinaryOperatorCode)
341 {
342 case kTfLiteBuiltinAdd:
343 return ValidateAddOperator(delegateData,
344 tfLiteContext,
345 inputTensorInfo0,
346 inputTensorInfo1,
347 outputTensorInfo);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000348 case kTfLiteBuiltinDiv:
349 return ValidateDivOperator(delegateData,
350 tfLiteContext,
351 inputTensorInfo0,
352 inputTensorInfo1,
353 outputTensorInfo);
Jim Flynn4b2f3472021-10-13 21:20:07 +0100354 case kTfLiteBuiltinFloorDiv:
355 return ValidateFloorDivOperator(delegateData,
356 tfLiteContext,
357 inputTensorInfo0,
358 inputTensorInfo1,
359 outputTensorInfo);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000360 case kTfLiteBuiltinMaximum:
361 return ValidateMaximumOperator(delegateData,
362 tfLiteContext,
363 inputTensorInfo0,
364 inputTensorInfo1,
365 outputTensorInfo);
366 case kTfLiteBuiltinMinimum:
367 return ValidateMinimumOperator(delegateData,
368 tfLiteContext,
369 inputTensorInfo0,
370 inputTensorInfo1,
371 outputTensorInfo);
372 case kTfLiteBuiltinMul:
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000373 return ValidateMulOperator(delegateData,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000374 tfLiteContext,
375 inputTensorInfo0,
376 inputTensorInfo1,
377 outputTensorInfo);
John Mcloughlin0ec00872023-05-15 17:03:49 +0100378 case kTfLiteBuiltinPow:
379 return ValidatePowerOperator(delegateData,
380 tfLiteContext,
381 inputTensorInfo0,
382 inputTensorInfo1,
383 outputTensorInfo);
384 case kTfLiteBuiltinSquaredDifference:
385 return ValidateSquaredDifferenceOperator(delegateData,
386 tfLiteContext,
387 inputTensorInfo0,
388 inputTensorInfo1,
389 outputTensorInfo);
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000390 case kTfLiteBuiltinSub:
Sadik Armagan15f7fae2020-11-18 09:37:03 +0000391 return ValidateSubOperator(delegateData,
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000392 tfLiteContext,
393 inputTensorInfo0,
394 inputTensorInfo1,
395 outputTensorInfo);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000396 default:
397 return kTfLiteError;
398 }
399 }
400
401 armnn::IConnectableLayer* elementwiseBinaryLayer = nullptr;
Jim Flynn4b2f3472021-10-13 21:20:07 +0100402 MultiLayerFacade multiLayer;
Mike Kelly07169c82023-08-02 13:23:09 +0100403 std::string layerName;
Sadik Armagan67e95f22020-10-29 16:14:54 +0000404 switch(elementwiseBinaryOperatorCode)
405 {
406 case kTfLiteBuiltinAdd:
Mike Kelly07169c82023-08-02 13:23:09 +0100407 layerName = GetLayerName(armnn::BinaryOperation::Add, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000408 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100409 armnn::BinaryOperation::Add, layerName.c_str());
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000410 break;
411 case kTfLiteBuiltinDiv:
Mike Kelly07169c82023-08-02 13:23:09 +0100412 layerName = GetLayerName(armnn::BinaryOperation::Div, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000413 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100414 armnn::BinaryOperation::Div, layerName.c_str());
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000415 break;
Jim Flynn4b2f3472021-10-13 21:20:07 +0100416 case kTfLiteBuiltinFloorDiv:
417 {
Mike Kelly07169c82023-08-02 13:23:09 +0100418 auto layers = AddFloorDivLayer(delegateData, outputTensorInfo, nodeIndex);
Jim Flynn4b2f3472021-10-13 21:20:07 +0100419 multiLayer.AssignValues(layers.first, layers.second);
420 elementwiseBinaryLayer = &multiLayer;
421 }
422 break;
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000423 case kTfLiteBuiltinMaximum:
Mike Kelly07169c82023-08-02 13:23:09 +0100424 layerName = GetLayerName(armnn::BinaryOperation::Maximum, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000425 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100426 armnn::BinaryOperation::Maximum, layerName.c_str());
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000427 break;
428 case kTfLiteBuiltinMinimum:
Mike Kelly07169c82023-08-02 13:23:09 +0100429 layerName = GetLayerName(armnn::BinaryOperation::Minimum, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000430 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100431 armnn::BinaryOperation::Minimum, layerName.c_str());
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000432 break;
433 case kTfLiteBuiltinMul:
Mike Kelly07169c82023-08-02 13:23:09 +0100434 layerName = GetLayerName(armnn::BinaryOperation::Mul, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000435 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100436 armnn::BinaryOperation::Mul, layerName.c_str());
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000437 break;
John Mcloughlin0ec00872023-05-15 17:03:49 +0100438 case kTfLiteBuiltinPow:
Mike Kelly07169c82023-08-02 13:23:09 +0100439 layerName = GetLayerName(armnn::BinaryOperation::Power, nodeIndex);
John Mcloughlin0ec00872023-05-15 17:03:49 +0100440 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100441 armnn::BinaryOperation::Power, layerName.c_str());
John Mcloughlin0ec00872023-05-15 17:03:49 +0100442 break;
443 case kTfLiteBuiltinSquaredDifference:
Mike Kelly07169c82023-08-02 13:23:09 +0100444 layerName = GetLayerName(armnn::BinaryOperation::SqDiff, nodeIndex);
John Mcloughlin0ec00872023-05-15 17:03:49 +0100445 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100446 armnn::BinaryOperation::SqDiff, layerName.c_str());
John Mcloughlin0ec00872023-05-15 17:03:49 +0100447 break;
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000448 case kTfLiteBuiltinSub:
Mike Kelly07169c82023-08-02 13:23:09 +0100449 layerName = GetLayerName(armnn::BinaryOperation::Sub, nodeIndex);
Mike Kelly3ec30772023-03-08 13:47:17 +0000450 elementwiseBinaryLayer = delegateData.m_Network->AddElementwiseBinaryLayer(
Mike Kelly07169c82023-08-02 13:23:09 +0100451 armnn::BinaryOperation::Sub, layerName.c_str());
Sadik Armagan67e95f22020-10-29 16:14:54 +0000452 break;
453 default:
454 return kTfLiteError;
455 }
456 ARMNN_ASSERT(elementwiseBinaryLayer != nullptr);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000457 armnn::IOutputSlot& outputSlot = elementwiseBinaryLayer->GetOutputSlot(0);
458 outputSlot.SetTensorInfo(outputTensorInfo);
459
Sadik Armaganf7ac72c2021-05-05 15:03:50 +0100460 auto inputsTensorsProcess = ProcessInputs(elementwiseBinaryLayer,
461 delegateData,
462 tfLiteContext,
Mike Kelly07169c82023-08-02 13:23:09 +0100463 tfLiteNode,
464 nodeIndex);
Sadik Armaganf7ac72c2021-05-05 15:03:50 +0100465 if (inputsTensorsProcess == kTfLiteError)
Sadik Armagan05e9fd22020-11-17 12:01:47 +0000466 {
Sadik Armaganf7ac72c2021-05-05 15:03:50 +0100467 return inputsTensorsProcess;
Sadik Armagan05e9fd22020-11-17 12:01:47 +0000468 }
469
Ryan OSheaa544f0f2023-01-25 18:10:20 +0000470 if(Connect(elementwiseBinaryLayer, tfLiteNode, delegateData) != kTfLiteOk)
Sadik Armagan67e95f22020-10-29 16:14:54 +0000471 {
472 return kTfLiteError;
473 }
474
Sadik Armagan67e95f22020-10-29 16:14:54 +0000475 if (!tfLiteNodeParameters)
476 {
477 // No Activation
478 return kTfLiteOk;
479 }
Ryan OShea3ad2e142023-01-13 10:19:20 +0000480 // Check and Create Activation
Mike Kelly07169c82023-08-02 13:23:09 +0100481 return FusedActivation(tfLiteContext, tfLiteNode, activationType, elementwiseBinaryLayer, 0, delegateData,
482 nodeIndex);
Sadik Armagan62483be2020-10-23 17:14:43 +0100483}
484
485} // namespace armnnDelegate