blob: 64941f7c5ca4312aa5f1ddf6c6b097be74d6ab0b [file] [log] [blame]
Tracy Narine7306bbe2023-07-17 16:06:26 +01001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include <ClassicDelegateUtils.hpp>
9
10#include <armnn/utility/IgnoreUnused.hpp>
11
12#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>
16#include <tensorflow/lite/kernels/internal/tensor_ctypes.h>
17
18namespace armnnDelegate
19{
20
21
22
23TfLiteStatus ValidateReverseV2Operator(DelegateData& delegateData,
24 TfLiteContext* tfLiteContext,
25 const armnn::TensorInfo& inputInfo0,
26 const armnn::TensorInfo& inputInfo1,
27 const armnn::TensorInfo& outputInfo)
28{
29 bool isSupported = false;
30 FORWARD_LAYER_SUPPORT_FUNC("REVERSEV2",
31 tfLiteContext,
32 IsReverseV2Supported,
33 delegateData.m_Backends,
34 isSupported,
35 armnn::BackendId(),
36 inputInfo0,
37 inputInfo1,
38 outputInfo);
39
40 return isSupported ? kTfLiteOk : kTfLiteError;
41}
42
43TfLiteStatus VisitReverseV2Operator(DelegateData& delegateData,
44 TfLiteContext* tfLiteContext,
45 TfLiteNode* tfLiteNode,
46 int nodeIndex,
47 int32_t reverseV2OperatorCode)
48{
49 TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex));
50 TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex));
51
52 const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors;
53
54 // The first input contains the data that should be reversed
55 const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]];
56 if (IsDynamicTensor(tfLiteInputTensor))
57 {
58 TF_LITE_MAYBE_KERNEL_LOG(
59 tfLiteContext,
60 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
61 reverseV2OperatorCode, nodeIndex);
62 return kTfLiteError;
63 }
64
65 // The second input contains an axis tensor.
66 const TfLiteTensor& tfLiteAxisTensor = tfLiteTensors[tfLiteNode->inputs->data[1]];
67 if (IsDynamicTensor(tfLiteAxisTensor))
68 {
69 TF_LITE_MAYBE_KERNEL_LOG(
70 tfLiteContext,
71 "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ",
72 reverseV2OperatorCode, nodeIndex);
73 return kTfLiteError;
74 }
75
76 // Get the output tensor
77 const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]];
78 if (IsDynamicTensor(tfLiteOutputTensor))
79 {
80 TF_LITE_MAYBE_KERNEL_LOG(
81 tfLiteContext,
82 "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ",
83 reverseV2OperatorCode, nodeIndex);
84 return kTfLiteError;
85 }
86
87 const armnn::TensorInfo& inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor);
88 const armnn::TensorInfo& inputTensorInfo1 = GetTensorInfoForTfLiteTensor(tfLiteAxisTensor);
89 const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true);
90
91 if (inputTensorInfo0.GetNumDimensions() != outputTensorInfo.GetNumDimensions())
92 {
93 TF_LITE_MAYBE_KERNEL_LOG(
94 tfLiteContext,
95 "TfLiteArmnnDelegate: input tensor dimension and output tensor dimension differ #%d node #%d: ",
96 reverseV2OperatorCode, nodeIndex);
97 return kTfLiteError;
98 }
99
100 for (unsigned i=0; i < inputTensorInfo0.GetNumDimensions(); i++)
101 {
102 if (inputTensorInfo0.GetShape()[i] != outputTensorInfo.GetShape()[i])
103 {
104 TF_LITE_MAYBE_KERNEL_LOG(
105 tfLiteContext,
106 "TfLiteArmnnDelegate: input tensor dimension and output tensor differ #%d node #%d: ",
107 reverseV2OperatorCode, nodeIndex);
108 return kTfLiteError;
109 }
110 }
111
Tracy Narine7306bbe2023-07-17 16:06:26 +0100112 const auto maxDimension = 4;
113
114 const auto axisTensorNumValues = static_cast<unsigned int>(tfLiteAxisTensor.dims->size);
115 if (axisTensorNumValues > maxDimension)
116 {
117 TF_LITE_MAYBE_KERNEL_LOG(
118 tfLiteContext,
119 "TfLiteArmnnDelegate: The Axis-Input-Tensor of the ReverseV2 operation requires a "
120 "dimension of <= %d but a tensor with a dimension of %d was given. "
121 "Operator: #%d node #%d: ",
122 maxDimension, axisTensorNumValues, reverseV2OperatorCode, nodeIndex);
123 return kTfLiteError;
124 }
125
126 // No network pointer indicates that only support for this operator should be checked
127 if (!delegateData.m_Network)
128 {
129 return ValidateReverseV2Operator(delegateData,
130 tfLiteContext,
131 inputTensorInfo0,
132 inputTensorInfo1,
133 outputTensorInfo);
134 }
135
Mike Kelly07169c82023-08-02 13:23:09 +0100136 auto layerName = GetLayerName(armnn::LayerType::ReverseV2, nodeIndex);
Tracy Narine7306bbe2023-07-17 16:06:26 +0100137 armnn::IConnectableLayer* reverseV2Layer = delegateData.m_Network->AddReverseV2Layer(layerName.c_str());
138
139 armnn::IOutputSlot& outputSlot = reverseV2Layer->GetOutputSlot(0);
140 outputSlot.SetTensorInfo(outputTensorInfo);
141
142 // Try to connect the Constant Inputs if there are any
Mike Kelly07169c82023-08-02 13:23:09 +0100143 if (ProcessInputs(reverseV2Layer, delegateData, tfLiteContext, tfLiteNode, nodeIndex) != kTfLiteOk)
Tracy Narine7306bbe2023-07-17 16:06:26 +0100144 {
145 return kTfLiteError;
146 }
147
148 ARMNN_ASSERT(reverseV2Layer != nullptr);
149
150 return Connect(reverseV2Layer, tfLiteNode, delegateData);
151}
152
153} // namespace armnnDelegate