xref: /aosp_15_r20/external/armnn/src/backends/neon/NeonLayerSupport.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "NeonLayerSupport.hpp"
7 #include "NeonBackendId.hpp"
8 #include "NeonBackendModelContext.hpp"
9 
10 #include <armnn/Exceptions.hpp>
11 #include <armnn/Tensor.hpp>
12 #include <armnn/Types.hpp>
13 #include <armnn/BackendRegistry.hpp>
14 
15 #include <InternalTypes.hpp>
16 #include <LayerSupportCommon.hpp>
17 #include <armnn/utility/IgnoreUnused.hpp>
18 #include <armnn/utility/PolymorphicDowncast.hpp>
19 
20 #if defined(ARMCOMPUTENEON_ENABLED)
21 #include <aclCommon/ArmComputeUtils.hpp>
22 #include <aclCommon/ArmComputeTensorUtils.hpp>
23 #include "workloads/NeonAbsWorkload.hpp"
24 #include "workloads/NeonAdditionWorkload.hpp"
25 #include "workloads/NeonActivationWorkload.hpp"
26 #include "workloads/NeonArgMinMaxWorkload.hpp"
27 #include "workloads/NeonBatchMatMulWorkload.hpp"
28 #include "workloads/NeonBatchNormalizationWorkload.hpp"
29 #include "workloads/NeonBatchToSpaceNdWorkload.hpp"
30 #include "workloads/NeonCastWorkload.hpp"
31 #include "workloads/NeonChannelShuffleWorkload.hpp"
32 #include "workloads/NeonComparisonWorkload.hpp"
33 #include "workloads/NeonConcatWorkload.hpp"
34 #include "workloads/NeonConstantWorkload.hpp"
35 #include "workloads/NeonConvolution2dWorkload.hpp"
36 #include "workloads/NeonConvolution3dWorkload.hpp"
37 #include "workloads/NeonDepthToSpaceWorkload.hpp"
38 #include "workloads/NeonDepthwiseConvolutionWorkload.hpp"
39 #include "workloads/NeonDequantizeWorkload.hpp"
40 #include "workloads/NeonExpWorkload.hpp"
41 #include "workloads/NeonInstanceNormalizationWorkload.hpp"
42 #include "workloads/NeonL2NormalizationFloatWorkload.hpp"
43 #include "workloads/NeonLogWorkload.hpp"
44 #include "workloads/NeonLogSoftmaxWorkload.hpp"
45 #include "workloads/NeonLogicalAndWorkload.hpp"
46 #include "workloads/NeonLogicalNotWorkload.hpp"
47 #include "workloads/NeonLogicalOrWorkload.hpp"
48 #include "workloads/NeonLstmFloatWorkload.hpp"
49 #include "workloads/NeonMaximumWorkload.hpp"
50 #include "workloads/NeonMeanWorkload.hpp"
51 #include "workloads/NeonMinimumWorkload.hpp"
52 #include "workloads/NeonMultiplicationWorkload.hpp"
53 #include "workloads/NeonDivisionWorkload.hpp"
54 #include "workloads/NeonNegWorkload.hpp"
55 #include "workloads/NeonNormalizationFloatWorkload.hpp"
56 #include "workloads/NeonFullyConnectedWorkload.hpp"
57 #include "workloads/NeonGatherWorkload.hpp"
58 #include "workloads/NeonGatherNdWorkload.hpp"
59 #include "workloads/NeonPadWorkload.hpp"
60 #include "workloads/NeonPermuteWorkload.hpp"
61 #include "workloads/NeonPooling2dWorkload.hpp"
62 #include "workloads/NeonPooling3dWorkload.hpp"
63 #include "workloads/NeonPreluWorkload.hpp"
64 #include "workloads/NeonQLstmWorkload.hpp"
65 #include "workloads/NeonQuantizeWorkload.hpp"
66 #include "workloads/NeonQuantizedLstmWorkload.hpp"
67 #include "workloads/NeonReduceWorkload.hpp"
68 #include "workloads/NeonReshapeWorkload.hpp"
69 #include "workloads/NeonResizeWorkload.hpp"
70 #include "workloads/NeonRsqrtWorkload.hpp"
71 #include "workloads/NeonSinWorkload.hpp"
72 #include "workloads/NeonSliceWorkload.hpp"
73 #include "workloads/NeonSoftmaxWorkload.hpp"
74 #include "workloads/NeonSpaceToBatchNdWorkload.hpp"
75 #include "workloads/NeonSpaceToDepthWorkload.hpp"
76 #include "workloads/NeonSplitterWorkload.hpp"
77 #include "workloads/NeonSqrtWorkload.hpp"
78 #include "workloads/NeonStackWorkload.hpp"
79 #include "workloads/NeonStridedSliceWorkload.hpp"
80 #include "workloads/NeonSubtractionWorkload.hpp"
81 #include "workloads/NeonTransposeConvolution2dWorkload.hpp"
82 #include "workloads/NeonTransposeWorkload.hpp"
83 #include "workloads/NeonUnidirectionalSequenceLstmFloatWorkload.hpp"
84 #include "workloads/NeonUnidirectionalSequenceLstmWorkload.hpp"
85 #endif
86 
87 namespace armnn
88 {
89 
90 namespace
91 {
92 
OverrideDataType(const TensorInfo & info,Optional<DataType> type)93 const TensorInfo OverrideDataType(const TensorInfo& info, Optional<DataType> type)
94 {
95     if (!type)
96     {
97         return info;
98     }
99     return TensorInfo(info.GetShape(),
100                       type.value(),
101                       info.GetQuantizationScale(),
102                       info.GetQuantizationOffset(),
103                       info.IsConstant());
104 }
105 
106 template< typename ... Args>
IsNeonBackendSupported(Optional<std::string &> reasonIfUnsupported,Args...args)107 bool IsNeonBackendSupported(Optional<std::string&> reasonIfUnsupported, Args... args)
108 {
109     IgnoreUnused(reasonIfUnsupported, (args)...);
110 #if defined(ARMCOMPUTENEON_ENABLED)
111     return true;
112 #else
113     SetValueChecked(reasonIfUnsupported, "The armnn library has been built without NEON support");
114     return false;
115 #endif
116 }
117 
118 template<typename FloatFunc, typename Uint8Func, typename ... Params>
IsSupportedForDataTypeNeon(Optional<std::string &> reasonIfUnsupported,DataType dataType,FloatFunc floatFuncPtr,Uint8Func uint8FuncPtr,Params &&...params)119 bool IsSupportedForDataTypeNeon(Optional<std::string&> reasonIfUnsupported,
120                                 DataType dataType,
121                                 FloatFunc floatFuncPtr,
122                                 Uint8Func uint8FuncPtr,
123                                 Params&&... params)
124 {
125     return IsNeonBackendSupported(reasonIfUnsupported) &&
126         IsSupportedForDataTypeGeneric(reasonIfUnsupported,
127                                          dataType,
128                                          floatFuncPtr,
129                                          floatFuncPtr,
130                                          uint8FuncPtr,
131                                          &FalseFunc<>,
132                                          &FalseFunc<>,
133                                          std::forward<Params>(params)...);
134 }
135 
136 #if defined(ARMCOMPUTENEON_ENABLED)
137 template<class FuncType, class... Args>
IsWorkloadSupported(FuncType & func,Optional<std::string &> reasonIfUnsupported,Args &&...args)138 inline bool IsWorkloadSupported(FuncType& func, Optional<std::string&> reasonIfUnsupported, Args&&... args)
139 {
140     arm_compute::Status aclStatus = func(std::forward<Args>(args)...);
141     const bool supported = (aclStatus.error_code() == arm_compute::ErrorCode::OK);
142     if (!supported && reasonIfUnsupported)
143     {
144         reasonIfUnsupported.value() = aclStatus.error_description();
145     }
146     return supported;
147 }
148 
149 #define FORWARD_WORKLOAD_VALIDATE_FUNC(func, reasonIfUnsupported, ...) \
150     return IsWorkloadSupported(func, reasonIfUnsupported, __VA_ARGS__);
151 #else
152 #define FORWARD_WORKLOAD_VALIDATE_FUNC(func, reasonIfUnsupported, ...) \
153     return IsNeonBackendSupported(reasonIfUnsupported, __VA_ARGS__);
154 #endif
155 } // anonymous namespace
156 
NeonLayerSupport(const IBackendInternal::IBackendSpecificModelContextPtr & modelContextPtr)157 NeonLayerSupport::NeonLayerSupport(const IBackendInternal::IBackendSpecificModelContextPtr& modelContextPtr)
158     : m_ModelContextPtr(modelContextPtr)
159 {
160 }
161 
NeonLayerSupport()162 NeonLayerSupport::NeonLayerSupport()
163     : m_ModelContextPtr(nullptr)
164 {
165 }
166 
IsLayerTypeSupported(const LayerType & type,const std::vector<TensorInfo> & infos,const BaseDescriptor & descriptor,const Optional<LstmInputParamsInfo> & lstmParamsInfo,const Optional<QuantizedLstmInputParamsInfo> & quantizedLstmParamsInfo,Optional<std::string &> reasonIfUnsupported,const NeonLayerSupport & support)167 bool IsLayerTypeSupported(const LayerType& type,
168                           const std::vector<TensorInfo>& infos,
169                           const BaseDescriptor& descriptor,
170                           const Optional<LstmInputParamsInfo>& lstmParamsInfo,
171                           const Optional<QuantizedLstmInputParamsInfo>& quantizedLstmParamsInfo,
172                           Optional<std::string&> reasonIfUnsupported,
173                           const NeonLayerSupport& support)
174 {
175     switch (type)
176     {
177         case LayerType::Activation:
178             return support.IsActivationSupported(infos[0],
179                                                  infos[1],
180                                                  *(PolymorphicDowncast<const ActivationDescriptor*>(&descriptor)),
181                                                  reasonIfUnsupported);
182         case LayerType::Addition:
183             return support.IsAdditionSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
184         case LayerType::ArgMinMax:
185             return support.IsArgMinMaxSupported(infos[0],
186                                                 infos[1],
187                                                 *(PolymorphicDowncast<const ArgMinMaxDescriptor*>(&descriptor)),
188                                                 reasonIfUnsupported);
189         case LayerType::BatchMatMul:
190             return support.IsBatchMatMulSupported(infos[0],
191                                                   infos[1],
192                                                   infos[2],
193                                                   *(PolymorphicDowncast<const BatchMatMulDescriptor*>(&descriptor)),
194                                                   reasonIfUnsupported);
195         case LayerType::BatchNormalization:
196             return support.IsBatchNormalizationSupported(infos[0],
197                                                          infos[1],
198                                                          infos[2],
199                                                          infos[3],
200                                                          infos[4],
201                                                          infos[5],
202                                                          *(PolymorphicDowncast<const
203                                                              BatchNormalizationDescriptor*>(&descriptor)),
204                                                          reasonIfUnsupported);
205         case LayerType::BatchToSpaceNd:
206             return support.IsBatchToSpaceNdSupported(infos[0],
207                                                      infos[1],
208                                                      *(PolymorphicDowncast<const
209                                                         BatchToSpaceNdDescriptor*>(&descriptor)),
210                                                      reasonIfUnsupported);
211         case LayerType::Cast:
212             return support.IsCastSupported(infos[0], infos[1], reasonIfUnsupported);
213         case LayerType::ChannelShuffle:
214             return support.IsChannelShuffleSupported(infos[0],
215                                                      infos[1],
216                                                      *(PolymorphicDowncast<const
217                                                          ChannelShuffleDescriptor*>(&descriptor)),
218                                                      reasonIfUnsupported);
219         case LayerType::Comparison:
220             return support.IsComparisonSupported(infos[0],
221                                                  infos[1],
222                                                  infos[2],
223                                                  *(PolymorphicDowncast<const ComparisonDescriptor*>(&descriptor)),
224                                                  reasonIfUnsupported);
225         case LayerType::Concat:
226         {
227             std::vector<const TensorInfo*> inputInfos;
228             for (uint32_t i = 0; i < (infos.size() - 1); i++)
229             {
230                 inputInfos.push_back(&infos[i]);
231             }
232             return support.IsConcatSupported(inputInfos,
233                                              infos[infos.size() - 1],
234                                              *(PolymorphicDowncast<const OriginsDescriptor*>(&descriptor)),
235                                              reasonIfUnsupported);
236         }
237         case LayerType::Constant:
238             return support.IsConstantSupported(infos[0], reasonIfUnsupported);
239         case LayerType::ConvertFp16ToFp32:
240             return support.IsConvertFp16ToFp32Supported(infos[0], infos[1], reasonIfUnsupported);
241         case LayerType::ConvertFp32ToFp16:
242             return support.IsConvertFp32ToFp16Supported(infos[0], infos[1], reasonIfUnsupported);
243         case LayerType::Convolution2d:
244         {
245             if (infos.size() != 4)
246             {
247                 throw InvalidArgumentException("Invalid number of TransposeConvolution2d TensorInfos. "
248                                                "TensorInfos should be of format: {input, output, weights, biases}.");
249             }
250 
251             auto desc = *(PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor));
252             if (infos[3] == TensorInfo())
253             {
254                 return support.IsConvolution2dSupported(infos[0],
255                                                         infos[1],
256                                                         desc,
257                                                         infos[2],
258                                                         EmptyOptional(),
259                                                         reasonIfUnsupported);
260             }
261             else
262             {
263                 return support.IsConvolution2dSupported(infos[0],
264                                                         infos[1],
265                                                         desc,
266                                                         infos[2],
267                                                         infos[3],
268                                                         reasonIfUnsupported);
269             }
270         }
271         case LayerType::Convolution3d:
272         {
273             if (infos.size() != 4)
274             {
275                 throw InvalidArgumentException("Invalid number of Convolution3d TensorInfos. "
276                                                "TensorInfos should be of format: {input, output, weights, biases}.");
277             }
278 
279             auto desc = *(PolymorphicDowncast<const Convolution3dDescriptor*>(&descriptor));
280             if (infos[3] == TensorInfo())
281             {
282                 return support.IsConvolution3dSupported(infos[0],
283                                                         infos[1],
284                                                         desc,
285                                                         infos[2],
286                                                         EmptyOptional(),
287                                                         reasonIfUnsupported);
288             }
289             else
290             {
291                 return support.IsConvolution3dSupported(infos[0],
292                                                         infos[1],
293                                                         desc,
294                                                         infos[2],
295                                                         infos[3],
296                                                         reasonIfUnsupported);
297             }
298         }
299         case LayerType::DepthToSpace:
300             return support.IsDepthToSpaceSupported(infos[0],
301                                                    infos[1],
302                                                    *(PolymorphicDowncast<const DepthToSpaceDescriptor*>(&descriptor)),
303                                                    reasonIfUnsupported);
304         case LayerType::DepthwiseConvolution2d:
305         {
306             if (infos.size() != 4)
307             {
308                 throw InvalidArgumentException("Invalid number of DepthwiseConvolution2d TensorInfos. "
309                                                "TensorInfos should be of format: {input, output, weights, biases}.");
310             }
311 
312             auto desc = *(PolymorphicDowncast<const DepthwiseConvolution2dDescriptor*>(&descriptor));
313             if (infos[3] == TensorInfo())
314             {
315                 return support.IsDepthwiseConvolutionSupported(infos[0],
316                                                                infos[1],
317                                                                desc,
318                                                                infos[2],
319                                                                EmptyOptional(),
320                                                                reasonIfUnsupported);
321             }
322             else
323             {
324                 return support.IsDepthwiseConvolutionSupported(infos[0],
325                                                                infos[1],
326                                                                desc,
327                                                                infos[2],
328                                                                infos[3],
329                                                                reasonIfUnsupported);
330             }
331         }
332         case LayerType::Dequantize:
333             return support.IsDequantizeSupported(infos[0], infos[1], reasonIfUnsupported);
334         case LayerType::DetectionPostProcess:
335         {
336             auto desc = *(PolymorphicDowncast<const DetectionPostProcessDescriptor*>(&descriptor));
337             return support.IsDetectionPostProcessSupported(infos[0],
338                                                            infos[1],
339                                                            infos[2],
340                                                            infos[3],
341                                                            infos[4],
342                                                            infos[5],
343                                                            infos[6],
344                                                            desc,
345                                                            reasonIfUnsupported);
346         }
347         case LayerType::Division:
348             return support.IsDivisionSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
349         case LayerType::ElementwiseBinary:
350         {
351             auto desc = *(PolymorphicDowncast<const ElementwiseBinaryDescriptor *>(&descriptor));
352 
353             switch (desc.m_Operation)
354             {
355                 case BinaryOperation::Add:
356                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonAdditionWorkloadValidate,
357                                                    reasonIfUnsupported,
358                                                    infos[0],
359                                                    infos[1],
360                                                    infos[2],
361                                                    nullptr);
362                 case BinaryOperation::Div:
363                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDivisionWorkloadValidate,
364                                                    reasonIfUnsupported,
365                                                    infos[0],
366                                                    infos[1],
367                                                    infos[2],
368                                                    nullptr);
369                 case BinaryOperation::Maximum:
370                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMaximumWorkloadValidate,
371                                                    reasonIfUnsupported,
372                                                    infos[0],
373                                                    infos[1],
374                                                    infos[2]);
375                 case BinaryOperation::Minimum:
376                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMinimumWorkloadValidate,
377                                                    reasonIfUnsupported,
378                                                    infos[0],
379                                                    infos[1],
380                                                    infos[2]);
381                 case BinaryOperation::Mul:
382                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMultiplicationWorkloadValidate,
383                                                    reasonIfUnsupported,
384                                                    infos[0],
385                                                    infos[1],
386                                                    infos[2],
387                                                    nullptr);
388                 case BinaryOperation::Sub:
389                     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSubtractionWorkloadValidate,
390                                                    reasonIfUnsupported,
391                                                    infos[0],
392                                                    infos[1],
393                                                    infos[2],
394                                                    nullptr);
395                 default:
396                     return false;
397             }
398         }
399         case LayerType::ElementwiseUnary:
400             return support.IsElementwiseUnarySupported(infos[0],
401                                                        infos[1],
402                                                        *(PolymorphicDowncast<const
403                                                            ElementwiseUnaryDescriptor*>(&descriptor)),
404                                                        reasonIfUnsupported);
405         case LayerType::Fill:
406             return support.IsFillSupported(infos[0],
407                                            infos[1],
408                                            *(PolymorphicDowncast<const FillDescriptor*>(&descriptor)),
409                                            reasonIfUnsupported);
410         case LayerType::Floor:
411             return support.IsFloorSupported(infos[0], infos[1], reasonIfUnsupported);
412         case LayerType::FullyConnected:
413             return support.IsFullyConnectedSupported(infos[0],
414                                                      infos[1],
415                                                      infos[2],
416                                                      infos[3],
417                                                      *(PolymorphicDowncast<const
418                                                          FullyConnectedDescriptor*>(&descriptor)),
419                                                      reasonIfUnsupported);
420         case LayerType::Gather:
421             return support.IsGatherSupported(infos[0],
422                                              infos[1],
423                                              infos[2],
424                                              *(PolymorphicDowncast<const GatherDescriptor*>(&descriptor)),
425                                              reasonIfUnsupported);
426         case LayerType::GatherNd:
427             return support.IsGatherNdSupported(infos[0],
428                                                infos[1],
429                                                infos[2],
430                                                reasonIfUnsupported);
431         case LayerType::Input:
432             return support.IsInputSupported(infos[0], reasonIfUnsupported);
433         case LayerType::InstanceNormalization:
434             return support.IsInstanceNormalizationSupported(infos[0],
435                                                             infos[1],
436                                                             *(PolymorphicDowncast<const
437                                                                 InstanceNormalizationDescriptor*>(&descriptor)),
438                                                             reasonIfUnsupported);
439         case LayerType::L2Normalization:
440             return support.IsL2NormalizationSupported(infos[0],
441                                                       infos[1],
442                                                       *(PolymorphicDowncast<const
443                                                           L2NormalizationDescriptor*>(&descriptor)),
444                                                       reasonIfUnsupported);
445         case LayerType::LogicalBinary:
446             return support.IsLogicalBinarySupported(infos[0],
447                                                     infos[1],
448                                                     infos[2],
449                                                     *(PolymorphicDowncast<const
450                                                         LogicalBinaryDescriptor*>(&descriptor)),
451                                                     reasonIfUnsupported);
452         case LayerType::LogSoftmax:
453             return support.IsLogSoftmaxSupported(infos[0],
454                                                  infos[1],
455                                                  *(PolymorphicDowncast<const LogSoftmaxDescriptor*>(&descriptor)),
456                                                  reasonIfUnsupported);
457         case LayerType::Lstm:
458             return support.IsLstmSupported(infos[0],
459                                            infos[1],
460                                            infos[2],
461                                            infos[3],
462                                            infos[4],
463                                            infos[5],
464                                            infos[6],
465                                            *(PolymorphicDowncast<const LstmDescriptor*>(&descriptor)),
466                                            lstmParamsInfo.value(),
467                                            reasonIfUnsupported);
468         case LayerType::Map:
469             return true;
470         case LayerType::Maximum:
471             return support.IsMaximumSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
472         case LayerType::Mean:
473             return support.IsMeanSupported(infos[0],
474                                            infos[1],
475                                            *(PolymorphicDowncast<const MeanDescriptor*>(&descriptor)),
476                                            reasonIfUnsupported);
477         case LayerType::MemCopy:
478             return support.IsMemCopySupported(infos[0], infos[1], reasonIfUnsupported);
479         case LayerType::MemImport:
480             return support.IsMemImportSupported(infos[0], infos[1], reasonIfUnsupported);
481         case LayerType::Merge:
482             return support.IsMergeSupported(infos[0],
483                                                       infos[1],
484                                                       infos[2],
485                                                       reasonIfUnsupported);
486         case LayerType::Minimum:
487             return support.IsMinimumSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
488         case LayerType::Multiplication:
489             return support.IsMultiplicationSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
490         case LayerType::Normalization:
491             return support.IsNormalizationSupported(infos[0],
492                                                     infos[1],
493                                                     *(PolymorphicDowncast<const
494                                                         NormalizationDescriptor*>(&descriptor)),
495                                                     reasonIfUnsupported);
496         case LayerType::Output:
497             return support.IsOutputSupported(infos[0], reasonIfUnsupported);
498         case LayerType::Pad:
499             return support.IsPadSupported(infos[0],
500                                           infos[1],
501                                           *(PolymorphicDowncast<const PadDescriptor*>(&descriptor)),
502                                           reasonIfUnsupported);
503         case LayerType::Permute:
504             return support.IsPermuteSupported(infos[0],
505                                               infos[1],
506                                               *(PolymorphicDowncast<const PermuteDescriptor*>(&descriptor)),
507                                               reasonIfUnsupported);
508         case LayerType::Pooling2d:
509             return support.IsPooling2dSupported(infos[0],
510                                                 infos[1],
511                                                 *(PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor)),
512                                                 reasonIfUnsupported);
513         case LayerType::Pooling3d:
514             return support.IsPooling3dSupported(infos[0],
515                                                 infos[1],
516                                                 *(PolymorphicDowncast<const Pooling3dDescriptor*>(&descriptor)),
517                                                 reasonIfUnsupported);
518         case LayerType::Prelu:
519             return support.IsPreluSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
520         case LayerType::QLstm:
521             return support.IsQLstmSupported(infos[0],
522                                             infos[1],
523                                             infos[2],
524                                             infos[3],
525                                             infos[4],
526                                             infos[5],
527                                             *(PolymorphicDowncast<const QLstmDescriptor*>(&descriptor)),
528                                             lstmParamsInfo.value(),
529                                             reasonIfUnsupported);
530         case LayerType::Quantize:
531             return support.IsQuantizeSupported(infos[0], infos[1], reasonIfUnsupported);
532         case LayerType::QuantizedLstm:
533             return support.IsQuantizedLstmSupported(infos[0],
534                                                     infos[1],
535                                                     infos[2],
536                                                     infos[3],
537                                                     infos[4],
538                                                     quantizedLstmParamsInfo.value(),
539                                                     reasonIfUnsupported);
540         case LayerType::Rank:
541             return true;
542         case LayerType::Reshape:
543             return support.IsReshapeSupported(infos[0],
544                                               infos[1],
545                                               *(PolymorphicDowncast<const ReshapeDescriptor*>(&descriptor)),
546                                               reasonIfUnsupported);
547         case LayerType::Resize:
548             return support.IsResizeSupported(infos[0],
549                                              infos[1],
550                                              *(PolymorphicDowncast<const ResizeDescriptor*>(&descriptor)),
551                                              reasonIfUnsupported);
552         case LayerType::Reduce:
553             return support.IsReduceSupported(infos[0],
554                                              infos[1],
555                                              *(PolymorphicDowncast<const ReduceDescriptor*>(&descriptor)),
556                                              reasonIfUnsupported);
557         case LayerType::Shape:
558             return support.IsShapeSupported(infos[0],
559                                             infos[1],
560                                             reasonIfUnsupported);
561         case LayerType::Slice:
562             return support.IsSliceSupported(infos[0],
563                                             infos[1],
564                                             *(PolymorphicDowncast<const SliceDescriptor*>(&descriptor)),
565                                             reasonIfUnsupported);
566         case LayerType::Softmax:
567             return support.IsSoftmaxSupported(infos[0],
568                                               infos[1],
569                                               *(PolymorphicDowncast<const SoftmaxDescriptor*>(&descriptor)),
570                                               reasonIfUnsupported);
571         case LayerType::SpaceToBatchNd:
572             return support.IsSpaceToBatchNdSupported(infos[0],
573                                                      infos[1],
574                                                      *(PolymorphicDowncast<const
575                                                         SpaceToBatchNdDescriptor*>(&descriptor)),
576                                                      reasonIfUnsupported);
577         case LayerType::SpaceToDepth:
578             return support.IsSpaceToDepthSupported(infos[0],
579                                                    infos[1],
580                                                    *(PolymorphicDowncast<const SpaceToDepthDescriptor*>(&descriptor)),
581                                                    reasonIfUnsupported);
582         case LayerType::Splitter:
583         {
584             std::vector<TensorInfo> outputInfos;
585             for (uint32_t i = 1; i < infos.size(); i++)
586             {
587                 outputInfos.push_back(infos[i]);
588             }
589             return support.IsSplitterSupported(infos[0],
590                                                {outputInfos.begin(), outputInfos.end()},
591                                                *(PolymorphicDowncast<const ViewsDescriptor*>(&descriptor)),
592                                                reasonIfUnsupported);
593         }
594         case LayerType::Stack:
595         {
596             std::vector<const TensorInfo*> inputInfos;
597             for (uint32_t i = 0; i < infos.size() - 1; i++)
598             {
599                 inputInfos.push_back(&infos[i]);
600             }
601             return support.IsStackSupported(inputInfos,
602                                             infos[infos.size() - 1],
603                                             *(PolymorphicDowncast<const StackDescriptor*>(&descriptor)),
604                                             reasonIfUnsupported);
605         }
606         case LayerType::StridedSlice:
607             return support.IsStridedSliceSupported(infos[0],
608                                                    infos[1],
609                                                    *(PolymorphicDowncast<const StridedSliceDescriptor*>(&descriptor)),
610                                                    reasonIfUnsupported);
611         case LayerType::Subtraction:
612             return support.IsSubtractionSupported(infos[0], infos[1], infos[2], reasonIfUnsupported);
613         case LayerType::Transpose:
614             return support.IsTransposeSupported(infos[0],
615                                                 infos[1],
616                                                 *(PolymorphicDowncast<const TransposeDescriptor*>(&descriptor)),
617                                                 reasonIfUnsupported);
618         case LayerType::TransposeConvolution2d:
619         {
620             if (infos.size() != 4)
621             {
622                 throw InvalidArgumentException("Invalid number of TransposeConvolution2d TensorInfos. "
623                                                "TensorInfos should be of format: {input, output, weights, biases}.");
624             }
625 
626             auto desc = *(PolymorphicDowncast<const TransposeConvolution2dDescriptor*>(&descriptor));
627             if (infos[3] == TensorInfo())
628             {
629                 return support.IsTransposeConvolution2dSupported(infos[0],
630                                                                  infos[1],
631                                                                  desc,
632                                                                  infos[2],
633                                                                  EmptyOptional(),
634                                                                  reasonIfUnsupported);
635             }
636             else
637             {
638                 return support.IsTransposeConvolution2dSupported(infos[0],
639                                                                  infos[1],
640                                                                  desc,
641                                                                  infos[2],
642                                                                  infos[3],
643                                                                  reasonIfUnsupported);
644             }
645         }
646         case LayerType::UnidirectionalSequenceLstm:
647         {
648             auto desc = *(PolymorphicDowncast<const UnidirectionalSequenceLstmDescriptor*>(&descriptor));
649             return support.IsUnidirectionalSequenceLstmSupported(infos[0],
650                                                                  infos[1],
651                                                                  infos[2],
652                                                                  infos[3],
653                                                                  infos[4],
654                                                                  infos[5],
655                                                                  desc,
656                                                                  lstmParamsInfo.value(),
657                                                                  reasonIfUnsupported);
658         }
659         case LayerType::Unmap:
660             return true;
661         default:
662             // layers not supported in neon by default:
663             // debug, fakequantization, precompiled,
664             // standin, switch
665             return false;
666     }
667 }
668 
IsLayerSupported(const LayerType & type,const std::vector<TensorInfo> & infos,const BaseDescriptor & descriptor,const Optional<LstmInputParamsInfo> & lstmParamsInfo,const Optional<QuantizedLstmInputParamsInfo> & quantizedLstmParamsInfo,Optional<std::string &> reasonIfUnsupported) const669 bool NeonLayerSupport::IsLayerSupported(const LayerType& type,
670                                         const std::vector<TensorInfo>& infos,
671                                         const BaseDescriptor& descriptor,
672                                         const Optional<LstmInputParamsInfo>& lstmParamsInfo,
673                                         const Optional<QuantizedLstmInputParamsInfo>& quantizedLstmParamsInfo,
674                                         Optional<std::string&> reasonIfUnsupported) const
675 {
676     bool isSupported = IsLayerTypeSupported(type,
677                                             infos,
678                                             descriptor,
679                                             lstmParamsInfo,
680                                             quantizedLstmParamsInfo,
681                                             reasonIfUnsupported,
682                                             *this);
683 
684     // For android-nn-driver and support library, to run FP16 operations on CpuAcc we need at least v8.2
685     // architecture. If the available architecture is older than v8.2, we can check if the operator is
686     // supported by changing operator inputs & outputs to be FP32.
687     // This does not change the operator datatype in the above parsers to be FP32. We are simply reporting
688     // to the parsers if the operator can supported in ArmNN. We will then re-enter ArmNN (Network.cpp)
689     // where we will recheck IsLayerSupported() on the FP16 datatype, update the operator to be FP32,
690     // and, insert convert layers around the FP32 operator.
691     if (reasonIfUnsupported.has_value())
692     {
693         std::string checkStr = "This CPU architecture does not support F16 data type, you need v8.2 or above";
694         if (!isSupported
695             && reasonIfUnsupported.value().find(checkStr) != std::string::npos)
696         {
697             std::vector<TensorInfo> newInfos;
698             for (auto               info: infos)
699             {
700                 newInfos.emplace_back(OverrideDataType(info, DataType::Float32));
701             }
702 
703             std::string tmpString;
704             return IsLayerTypeSupported(type,
705                                         newInfos,
706                                         descriptor,
707                                         lstmParamsInfo,
708                                         quantizedLstmParamsInfo,
709                                         tmpString,
710                                         *this);
711         }
712     }
713 
714     return isSupported;
715 }
716 
IsActivationSupported(const TensorInfo & input,const TensorInfo & output,const ActivationDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const717 bool NeonLayerSupport::IsActivationSupported(const TensorInfo& input,
718                                              const TensorInfo& output,
719                                              const ActivationDescriptor& descriptor,
720                                              Optional<std::string&> reasonIfUnsupported) const
721 {
722     IgnoreUnused(descriptor);
723     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonActivationWorkloadValidate,
724                                    reasonIfUnsupported,
725                                    input,
726                                    output,
727                                    descriptor);
728 }
729 
IsAdditionSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const730 bool NeonLayerSupport::IsAdditionSupported(const TensorInfo& input0,
731                                            const TensorInfo& input1,
732                                            const TensorInfo& output,
733                                            Optional<std::string&> reasonIfUnsupported) const
734 {
735     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonAdditionWorkloadValidate,
736                                    reasonIfUnsupported,
737                                    input0,
738                                    input1,
739                                    output,
740                                    nullptr);
741 }
742 
IsArgMinMaxSupported(const TensorInfo & input,const TensorInfo & output,const ArgMinMaxDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const743 bool NeonLayerSupport::IsArgMinMaxSupported(const TensorInfo& input,
744                                             const TensorInfo& output,
745                                             const ArgMinMaxDescriptor& descriptor,
746                                             Optional<std::string&> reasonIfUnsupported) const
747 {
748     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonArgMinMaxWorkloadValidate,
749                                    reasonIfUnsupported,
750                                    input,
751                                    output,
752                                    descriptor);
753 }
754 
IsBatchMatMulSupported(const TensorInfo & inputX,const TensorInfo & inputY,const TensorInfo & output,const BatchMatMulDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const755 bool NeonLayerSupport::IsBatchMatMulSupported(const TensorInfo& inputX,
756                                               const TensorInfo& inputY,
757                                               const TensorInfo& output,
758                                               const BatchMatMulDescriptor& descriptor,
759                                               Optional<std::string&> reasonIfUnsupported) const
760 {
761     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonBatchMatMulValidate,
762                                    reasonIfUnsupported,
763                                    inputX,
764                                    inputY,
765                                    output,
766                                    descriptor);
767 }
768 
IsBatchNormalizationSupported(const TensorInfo & input,const TensorInfo & output,const TensorInfo & mean,const TensorInfo & var,const TensorInfo & beta,const TensorInfo & gamma,const BatchNormalizationDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const769 bool NeonLayerSupport::IsBatchNormalizationSupported(const TensorInfo& input,
770                                                      const TensorInfo& output,
771                                                      const TensorInfo& mean,
772                                                      const TensorInfo& var,
773                                                      const TensorInfo& beta,
774                                                      const TensorInfo& gamma,
775                                                      const BatchNormalizationDescriptor& descriptor,
776                                                      Optional<std::string&> reasonIfUnsupported) const
777 {
778     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonBatchNormalizationValidate,
779                                    reasonIfUnsupported,
780                                    input,
781                                    output,
782                                    mean,
783                                    var,
784                                    beta,
785                                    gamma,
786                                    descriptor,
787                                    nullptr);
788 }
789 
IsBatchToSpaceNdSupported(const TensorInfo & input,const TensorInfo & output,const BatchToSpaceNdDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const790 bool NeonLayerSupport::IsBatchToSpaceNdSupported(const TensorInfo& input,
791                                                  const TensorInfo& output,
792                                                  const BatchToSpaceNdDescriptor& descriptor,
793                                                  Optional<std::string&> reasonIfUnsupported) const
794 {
795     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonBatchToSpaceNdWorkloadValidate,
796                                    reasonIfUnsupported,
797                                    input,
798                                    output,
799                                    descriptor);
800 }
801 
IsCastSupported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const802 bool NeonLayerSupport::IsCastSupported(const TensorInfo& input,
803                                        const TensorInfo& output,
804                                        Optional<std::string&> reasonIfUnsupported) const
805 {
806     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonCastValidate,
807                                    reasonIfUnsupported,
808                                    input,
809                                    output);
810 }
811 
IsChannelShuffleSupported(const TensorInfo & input,const TensorInfo & output,const ChannelShuffleDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const812 bool NeonLayerSupport::IsChannelShuffleSupported(const TensorInfo& input,
813                                                  const TensorInfo& output,
814                                                  const ChannelShuffleDescriptor& descriptor,
815                                                  Optional<std::string&> reasonIfUnsupported) const
816 {
817     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonChannelShuffleValidate,
818                                    reasonIfUnsupported,
819                                    input,
820                                    output,
821                                    descriptor);
822 }
823 
IsComparisonSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,const ComparisonDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const824 bool NeonLayerSupport::IsComparisonSupported(const TensorInfo& input0,
825                                              const TensorInfo& input1,
826                                              const TensorInfo& output,
827                                              const ComparisonDescriptor& descriptor,
828                                              Optional<std::string&> reasonIfUnsupported) const
829 {
830 
831     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonComparisonWorkloadValidate,
832                                    reasonIfUnsupported,
833                                    input0,
834                                    input1,
835                                    output,
836                                    descriptor);
837 }
838 
IsConcatSupported(const std::vector<const TensorInfo * > inputs,const TensorInfo & output,const OriginsDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const839 bool NeonLayerSupport::IsConcatSupported(const std::vector<const TensorInfo*> inputs,
840                                          const TensorInfo& output,
841                                          const OriginsDescriptor& descriptor,
842                                          Optional<std::string&> reasonIfUnsupported) const
843 {
844     if (descriptor.GetNumDimensions() <= descriptor.GetConcatAxis())
845     {
846         SetValueChecked(reasonIfUnsupported, "Neon Concat: Concat axis > Number of dimensions.");
847         return false;
848     }
849 
850     unsigned int concatInnerAxis = (descriptor.GetNumDimensions() - descriptor.GetConcatAxis()) - 1;
851     if(concatInnerAxis < 3) // Width, height, or channels
852     {
853         FORWARD_WORKLOAD_VALIDATE_FUNC(NeonConcatWorkloadValidate,
854                                        reasonIfUnsupported,
855                                        inputs,
856                                        output,
857                                        descriptor);
858     }
859     else if (concatInnerAxis == 3)
860     {
861         for (auto& input : inputs)
862         {
863             if (input && !output.IsTypeSpaceMatch(*input)) // Cannot use sub-tensors if the types are not same space
864             {
865                 SetValueChecked(reasonIfUnsupported, "Neon Concat: Types and quantization parameters must match.");
866                 return false;
867             }
868         }
869         return true; // Sub-tensors support concat along batch
870     }
871     else // > 4 dimensions not supported.
872     {
873         SetValueChecked(reasonIfUnsupported, "Neon Concat: Maximum of 4 dimensions supported.");
874         return false;
875     }
876 }
877 
IsConstantSupported(const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const878 bool NeonLayerSupport::IsConstantSupported(const TensorInfo& output,
879                                            Optional<std::string&> reasonIfUnsupported) const
880 {
881     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonConstantWorkloadValidate,
882                                    reasonIfUnsupported,
883                                    output);
884 }
885 
IsConvertFp16ToFp32Supported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const886 bool NeonLayerSupport::IsConvertFp16ToFp32Supported(const TensorInfo& input,
887                                                     const TensorInfo& output,
888                                                     Optional<std::string&> reasonIfUnsupported) const
889 {
890     armnn::IgnoreUnused(input);
891     armnn::IgnoreUnused(output);
892     armnn::IgnoreUnused(reasonIfUnsupported);
893     return true;
894 }
895 
IsConvertFp32ToFp16Supported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const896 bool NeonLayerSupport::IsConvertFp32ToFp16Supported(const TensorInfo& input,
897                                                     const TensorInfo& output,
898                                                     Optional<std::string&> reasonIfUnsupported) const
899 {
900     armnn::IgnoreUnused(input);
901     armnn::IgnoreUnused(output);
902     armnn::IgnoreUnused(reasonIfUnsupported);
903     return true;
904 }
905 
IsConvolution2dSupported(const TensorInfo & input,const TensorInfo & output,const Convolution2dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,Optional<std::string &> reasonIfUnsupported) const906 bool NeonLayerSupport::IsConvolution2dSupported(const TensorInfo& input,
907                                                 const TensorInfo& output,
908                                                 const Convolution2dDescriptor& descriptor,
909                                                 const TensorInfo& weights,
910                                                 const Optional<TensorInfo>& biases,
911                                                 Optional<std::string&> reasonIfUnsupported) const
912 {
913     bool isFastMathEnabled = false;
914 #if defined(ARMCOMPUTENEON_ENABLED)
915     if (m_ModelContextPtr)
916     {
917         if (m_ModelContextPtr.get() != nullptr)
918         {
919             auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
920             if (modelOptions)
921             {
922                 isFastMathEnabled = modelOptions->IsFastMathEnabled();
923             }
924         }
925     }
926 #endif
927 
928     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonConvolution2dWorkloadValidate,
929                                    reasonIfUnsupported,
930                                    input,
931                                    output,
932                                    descriptor,
933                                    weights,
934                                    biases,
935                                    isFastMathEnabled,
936                                    nullptr);
937 }
938 
IsConvolution3dSupported(const TensorInfo & input,const TensorInfo & output,const Convolution3dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,Optional<std::string &> reasonIfUnsupported) const939 bool NeonLayerSupport::IsConvolution3dSupported(const TensorInfo& input,
940                                                 const TensorInfo& output,
941                                                 const Convolution3dDescriptor& descriptor,
942                                                 const TensorInfo& weights,
943                                                 const Optional<TensorInfo>& biases,
944                                                 Optional<std::string&> reasonIfUnsupported) const
945 {
946     bool isFastMathEnabled = false;
947 #if defined(ARMCOMPUTENEON_ENABLED)
948     if (m_ModelContextPtr)
949     {
950         if (m_ModelContextPtr.get() != nullptr)
951         {
952             auto modelOptions = dynamic_cast<NeonBackendModelContext*>(m_ModelContextPtr.get());
953             if (modelOptions)
954             {
955                 isFastMathEnabled = modelOptions->IsFastMathEnabled();
956             }
957         }
958     }
959 #endif
960 
961     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonConvolution3dWorkloadValidate,
962                                    reasonIfUnsupported,
963                                    input,
964                                    output,
965                                    descriptor,
966                                    weights,
967                                    biases,
968                                    isFastMathEnabled,
969                                    nullptr);
970 }
971 
IsDepthToSpaceSupported(const TensorInfo & input,const TensorInfo & output,const DepthToSpaceDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const972 bool NeonLayerSupport::IsDepthToSpaceSupported(const TensorInfo& input,
973                                                const TensorInfo& output,
974                                                const DepthToSpaceDescriptor& descriptor,
975                                                Optional<std::string&> reasonIfUnsupported) const
976 {
977     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDepthToSpaceWorkloadValidate,
978                                    reasonIfUnsupported,
979                                    input,
980                                    output,
981                                    descriptor);
982 }
983 
IsDepthwiseConvolutionSupported(const TensorInfo & input,const TensorInfo & output,const DepthwiseConvolution2dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,Optional<std::string &> reasonIfUnsupported) const984 bool NeonLayerSupport::IsDepthwiseConvolutionSupported(const TensorInfo& input,
985                                                        const TensorInfo& output,
986                                                        const DepthwiseConvolution2dDescriptor& descriptor,
987                                                        const TensorInfo& weights,
988                                                        const Optional<TensorInfo>& biases,
989                                                        Optional<std::string&> reasonIfUnsupported) const
990 {
991     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDepthwiseConvolutionWorkloadValidate,
992                                    reasonIfUnsupported,
993                                    input,
994                                    output,
995                                    descriptor,
996                                    weights,
997                                    biases,
998                                    nullptr);
999 }
1000 
IsDequantizeSupported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1001 bool NeonLayerSupport::IsDequantizeSupported(const TensorInfo& input,
1002                                              const TensorInfo& output,
1003                                              Optional<std::string&> reasonIfUnsupported) const
1004 {
1005     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDequantizeWorkloadValidate,
1006                                    reasonIfUnsupported,
1007                                    input,
1008                                    output);
1009 }
1010 
IsDilatedDepthwiseConvolutionSupported(const TensorInfo & input,const TensorInfo & output,const DepthwiseConvolution2dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,Optional<std::string &> reasonIfUnsupported) const1011 bool NeonLayerSupport::IsDilatedDepthwiseConvolutionSupported(const TensorInfo& input,
1012                                                               const TensorInfo& output,
1013                                                               const DepthwiseConvolution2dDescriptor& descriptor,
1014                                                               const TensorInfo& weights,
1015                                                               const Optional<TensorInfo>& biases,
1016                                                               Optional<std::string&> reasonIfUnsupported) const
1017 {
1018     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDepthwiseConvolutionWorkloadValidate,
1019                                    reasonIfUnsupported,
1020                                    input,
1021                                    output,
1022                                    descriptor,
1023                                    weights,
1024                                    biases,
1025                                    nullptr);
1026 }
1027 
IsElementwiseUnarySupported(const TensorInfo & input,const TensorInfo & output,const ElementwiseUnaryDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1028 bool NeonLayerSupport::IsElementwiseUnarySupported(const TensorInfo& input,
1029                                                    const TensorInfo& output,
1030                                                    const ElementwiseUnaryDescriptor& descriptor,
1031                                                    Optional<std::string&> reasonIfUnsupported) const
1032 {
1033     switch(descriptor.m_Operation)
1034     {
1035         case UnaryOperation::Abs:
1036             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonAbsWorkloadValidate,
1037                                            reasonIfUnsupported,
1038                                            input,
1039                                            output);
1040         case UnaryOperation::Exp:
1041             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonExpWorkloadValidate,
1042                                            reasonIfUnsupported,
1043                                            input,
1044                                            output);
1045         case UnaryOperation::LogicalNot:
1046             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogicalNotWorkloadValidate,
1047                                            reasonIfUnsupported,
1048                                            input,
1049                                            output);
1050        case UnaryOperation::Log:
1051             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogWorkloadValidate,
1052                                            reasonIfUnsupported,
1053                                            input,
1054                                            output);
1055         case UnaryOperation::Neg:
1056             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonNegWorkloadValidate,
1057                                            reasonIfUnsupported,
1058                                            input,
1059                                            output);
1060         case UnaryOperation::Rsqrt:
1061             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonRsqrtWorkloadValidate,
1062                                            reasonIfUnsupported,
1063                                            input,
1064                                            output);
1065         case UnaryOperation::Sin:
1066             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSinWorkloadValidate,
1067                                            reasonIfUnsupported,
1068                                            input,
1069                                            output);
1070         case UnaryOperation::Sqrt:
1071             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSqrtWorkloadValidate,
1072                                            reasonIfUnsupported,
1073                                            input,
1074                                            output);
1075         default:
1076             return false;
1077     }
1078 }
1079 
IsFillSupported(const TensorInfo & input,const TensorInfo & output,const FillDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1080 bool NeonLayerSupport::IsFillSupported(const TensorInfo& input,
1081                                        const TensorInfo& output,
1082                                        const FillDescriptor& descriptor,
1083                                        Optional<std::string&> reasonIfUnsupported) const
1084 {
1085     armnn::IgnoreUnused(input);
1086     armnn::IgnoreUnused(output);
1087     armnn::IgnoreUnused(descriptor);
1088 
1089     return IsNeonBackendSupported(reasonIfUnsupported);
1090 }
1091 
IsFloorSupported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1092 bool NeonLayerSupport::IsFloorSupported(const TensorInfo& input,
1093                                         const TensorInfo& output,
1094                                         Optional<std::string&> reasonIfUnsupported) const
1095 {
1096     armnn::IgnoreUnused(output);
1097     return IsNeonBackendSupported(reasonIfUnsupported) &&
1098            IsSupportedForDataTypeGeneric(reasonIfUnsupported,
1099                                          input.GetDataType(),
1100                                          &FalseFuncF16<>,
1101                                          &TrueFunc<>,
1102                                          &FalseFuncU8<>,
1103                                          &FalseFuncI32<>,
1104                                          &FalseFuncU8<>);
1105 }
1106 
IsFullyConnectedSupported(const TensorInfo & input,const TensorInfo & output,const TensorInfo & weights,const TensorInfo & biases,const FullyConnectedDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1107 bool NeonLayerSupport::IsFullyConnectedSupported(const TensorInfo& input,
1108                                                  const TensorInfo& output,
1109                                                  const TensorInfo& weights,
1110                                                  const TensorInfo& biases,
1111                                                  const FullyConnectedDescriptor& descriptor,
1112                                                  Optional<std::string&> reasonIfUnsupported) const
1113 {
1114     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonFullyConnectedWorkloadValidate,
1115                                    reasonIfUnsupported,
1116                                    input,
1117                                    output,
1118                                    weights,
1119                                    biases,
1120                                    descriptor,
1121                                    nullptr);
1122 }
1123 
IsGatherSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,const GatherDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1124 bool NeonLayerSupport::IsGatherSupported(const TensorInfo& input0,
1125                                          const TensorInfo& input1,
1126                                          const TensorInfo& output,
1127                                          const GatherDescriptor& descriptor,
1128                                          Optional<std::string&> reasonIfUnsupported) const
1129 {
1130     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonGatherWorkloadValidate,
1131                                    reasonIfUnsupported,
1132                                    input0,
1133                                    input1,
1134                                    output,
1135                                    descriptor);
1136 }
1137 
IsGatherNdSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1138 bool NeonLayerSupport::IsGatherNdSupported(const TensorInfo& input0,
1139                                            const TensorInfo& input1,
1140                                            const TensorInfo& output,
1141                                            Optional<std::string&> reasonIfUnsupported) const
1142 {
1143     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonGatherNdWorkloadValidate,
1144                                    reasonIfUnsupported,
1145                                    input0,
1146                                    input1,
1147                                    output);
1148 }
1149 
IsInputSupported(const TensorInfo & input,Optional<std::string &> reasonIfUnsupported) const1150 bool NeonLayerSupport::IsInputSupported(const TensorInfo& input,
1151                                         Optional<std::string&> reasonIfUnsupported) const
1152 {
1153     return IsNeonBackendSupported(reasonIfUnsupported, input);
1154 }
1155 
IsInstanceNormalizationSupported(const TensorInfo & input,const TensorInfo & output,const InstanceNormalizationDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1156 bool NeonLayerSupport::IsInstanceNormalizationSupported(const TensorInfo& input,
1157                                                         const TensorInfo& output,
1158                                                         const InstanceNormalizationDescriptor& descriptor,
1159                                                         Optional<std::string&> reasonIfUnsupported) const
1160 {
1161     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonInstanceNormalizationWorkloadValidate,
1162                                    reasonIfUnsupported,
1163                                    input,
1164                                    output,
1165                                    descriptor);
1166 }
1167 
IsL2NormalizationSupported(const TensorInfo & input,const TensorInfo & output,const L2NormalizationDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1168 bool NeonLayerSupport::IsL2NormalizationSupported(const TensorInfo& input,
1169                                                   const TensorInfo& output,
1170                                                   const L2NormalizationDescriptor& descriptor,
1171                                                   Optional<std::string&> reasonIfUnsupported) const
1172 {
1173     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonL2NormalizationWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1174 }
1175 
IsLogicalBinarySupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,const LogicalBinaryDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1176 bool NeonLayerSupport::IsLogicalBinarySupported(const TensorInfo& input0,
1177                                                 const TensorInfo& input1,
1178                                                 const TensorInfo& output,
1179                                                 const LogicalBinaryDescriptor& descriptor,
1180                                                 Optional<std::string&> reasonIfUnsupported) const
1181 {
1182     switch(descriptor.m_Operation)
1183     {
1184         case LogicalBinaryOperation::LogicalAnd:
1185             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogicalAndWorkloadValidate,
1186                                            reasonIfUnsupported,
1187                                            input0,
1188                                            input1,
1189                                            output);
1190         case LogicalBinaryOperation::LogicalOr:
1191             FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogicalOrWorkloadValidate,
1192                                            reasonIfUnsupported,
1193                                            input0,
1194                                            input1,
1195                                            output);
1196         default:
1197             return false;
1198     }
1199 }
1200 
IsLogSoftmaxSupported(const TensorInfo & input,const TensorInfo & output,const LogSoftmaxDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1201 bool NeonLayerSupport::IsLogSoftmaxSupported(const TensorInfo& input,
1202                                              const TensorInfo& output,
1203                                              const LogSoftmaxDescriptor& descriptor,
1204                                              Optional<std::string&> reasonIfUnsupported) const
1205 {
1206     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLogSoftmaxWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1207 }
1208 
IsLstmSupported(const TensorInfo & input,const TensorInfo & outputStateIn,const TensorInfo & cellStateIn,const TensorInfo & scratchBuffer,const TensorInfo & outputStateOut,const TensorInfo & cellStateOut,const TensorInfo & output,const LstmDescriptor & descriptor,const LstmInputParamsInfo & paramsInfo,Optional<std::string &> reasonIfUnsupported) const1209 bool NeonLayerSupport::IsLstmSupported(const TensorInfo& input,
1210                                        const TensorInfo& outputStateIn,
1211                                        const TensorInfo& cellStateIn,
1212                                        const TensorInfo& scratchBuffer,
1213                                        const TensorInfo& outputStateOut,
1214                                        const TensorInfo& cellStateOut,
1215                                        const TensorInfo& output,
1216                                        const LstmDescriptor& descriptor,
1217                                        const LstmInputParamsInfo& paramsInfo,
1218                                        Optional<std::string&> reasonIfUnsupported) const
1219 {
1220     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonLstmFloatWorkloadValidate,
1221                                    reasonIfUnsupported,
1222                                    input,
1223                                    outputStateIn,
1224                                    cellStateIn,
1225                                    scratchBuffer,
1226                                    outputStateOut,
1227                                    cellStateOut,
1228                                    output,
1229                                    descriptor,
1230                                    paramsInfo);
1231 }
1232 
IsMaximumSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1233 bool NeonLayerSupport::IsMaximumSupported(const TensorInfo& input0,
1234                                           const TensorInfo& input1,
1235                                           const TensorInfo& output,
1236                                           Optional<std::string&> reasonIfUnsupported) const
1237 {
1238     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMaximumWorkloadValidate,
1239                                    reasonIfUnsupported,
1240                                    input0,
1241                                    input1,
1242                                    output);
1243 }
1244 
IsMeanSupported(const TensorInfo & input,const TensorInfo & output,const MeanDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1245 bool NeonLayerSupport::IsMeanSupported(const TensorInfo& input,
1246                                        const TensorInfo& output,
1247                                        const MeanDescriptor& descriptor,
1248                                        Optional<std::string&> reasonIfUnsupported) const
1249 {
1250     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMeanWorkloadValidate,
1251                                    reasonIfUnsupported,
1252                                    input,
1253                                    output,
1254                                    descriptor);
1255 }
1256 
IsMinimumSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1257 bool NeonLayerSupport::IsMinimumSupported(const TensorInfo& input0,
1258                                           const TensorInfo& input1,
1259                                           const TensorInfo& output,
1260                                           Optional<std::string&> reasonIfUnsupported) const
1261 {
1262     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMinimumWorkloadValidate,
1263                                    reasonIfUnsupported,
1264                                    input0,
1265                                    input1,
1266                                    output);
1267 }
1268 
IsMultiplicationSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1269 bool NeonLayerSupport::IsMultiplicationSupported(const TensorInfo& input0,
1270                                                  const TensorInfo& input1,
1271                                                  const TensorInfo& output,
1272                                                  Optional<std::string&> reasonIfUnsupported) const
1273 {
1274     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonMultiplicationWorkloadValidate,
1275                                    reasonIfUnsupported,
1276                                    input0,
1277                                    input1,
1278                                    output,
1279                                    nullptr);
1280 }
1281 
IsDivisionSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1282 bool NeonLayerSupport::IsDivisionSupported(const TensorInfo& input0,
1283                                            const TensorInfo& input1,
1284                                            const TensorInfo& output,
1285                                            Optional<std::string&> reasonIfUnsupported) const
1286 {
1287     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonDivisionWorkloadValidate,
1288                                    reasonIfUnsupported,
1289                                    input0,
1290                                    input1,
1291                                    output,
1292                                    nullptr);
1293 }
1294 
IsNormalizationSupported(const TensorInfo & input,const TensorInfo & output,const NormalizationDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1295 bool NeonLayerSupport::IsNormalizationSupported(const TensorInfo& input,
1296                                                 const TensorInfo& output,
1297                                                 const NormalizationDescriptor& descriptor,
1298                                                 Optional<std::string&> reasonIfUnsupported) const
1299 {
1300     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonNormalizationWorkloadValidate,
1301                                    reasonIfUnsupported,
1302                                    input,
1303                                    output,
1304                                    descriptor);
1305 }
1306 
IsOutputSupported(const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1307 bool NeonLayerSupport::IsOutputSupported(const TensorInfo& output,
1308                                          Optional<std::string&> reasonIfUnsupported) const
1309 {
1310     return IsNeonBackendSupported(reasonIfUnsupported, output);
1311 }
1312 
IsPadSupported(const TensorInfo & input,const TensorInfo & output,const PadDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1313 bool NeonLayerSupport::IsPadSupported(const TensorInfo& input,
1314                                       const TensorInfo& output,
1315                                       const PadDescriptor& descriptor,
1316                                       Optional<std::string&> reasonIfUnsupported) const
1317 {
1318     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonPadWorkloadValidate,
1319                                    reasonIfUnsupported,
1320                                    input,
1321                                    output,
1322                                    descriptor);
1323 }
1324 
IsPermuteSupported(const TensorInfo & input,const TensorInfo & output,const PermuteDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1325 bool NeonLayerSupport::IsPermuteSupported(const TensorInfo& input,
1326                                           const TensorInfo& output,
1327                                           const PermuteDescriptor& descriptor,
1328                                           Optional<std::string&> reasonIfUnsupported) const
1329 {
1330     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonPermuteWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1331 }
1332 
IsPooling2dSupported(const TensorInfo & input,const TensorInfo & output,const Pooling2dDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1333 bool NeonLayerSupport::IsPooling2dSupported(const TensorInfo& input,
1334                                             const TensorInfo& output,
1335                                             const Pooling2dDescriptor& descriptor,
1336                                             Optional<std::string&> reasonIfUnsupported) const
1337 {
1338     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonPooling2dWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1339 }
1340 
IsPooling3dSupported(const TensorInfo & input,const TensorInfo & output,const Pooling3dDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1341 bool NeonLayerSupport::IsPooling3dSupported(const TensorInfo& input,
1342                                             const TensorInfo& output,
1343                                             const Pooling3dDescriptor& descriptor,
1344                                             Optional<std::string&> reasonIfUnsupported) const
1345 {
1346     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonPooling3dWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1347 }
1348 
IsPreluSupported(const armnn::TensorInfo & input,const armnn::TensorInfo & alpha,const armnn::TensorInfo & output,armnn::Optional<std::string &> reasonIfUnsupported) const1349 bool NeonLayerSupport::IsPreluSupported(const armnn::TensorInfo &input,
1350                                         const armnn::TensorInfo &alpha,
1351                                         const armnn::TensorInfo &output,
1352                                         armnn::Optional<std::string &> reasonIfUnsupported) const
1353 {
1354     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonPreluWorkloadValidate, reasonIfUnsupported, input, alpha, output);
1355 }
1356 
IsQLstmSupported(const TensorInfo & input,const TensorInfo & previousOutputIn,const TensorInfo & previousCellStateIn,const TensorInfo & outputStateOut,const TensorInfo & cellStateOut,const TensorInfo & output,const QLstmDescriptor & descriptor,const LstmInputParamsInfo & paramsInfo,Optional<std::string &> reasonIfUnsupported) const1357 bool NeonLayerSupport::IsQLstmSupported(const TensorInfo& input,
1358                                         const TensorInfo& previousOutputIn,
1359                                         const TensorInfo& previousCellStateIn,
1360                                         const TensorInfo& outputStateOut,
1361                                         const TensorInfo& cellStateOut,
1362                                         const TensorInfo& output,
1363                                         const QLstmDescriptor& descriptor,
1364                                         const LstmInputParamsInfo& paramsInfo,
1365                                         Optional<std::string&> reasonIfUnsupported) const
1366 {
1367     // Check required here in order to pass IsLayerSupported for datatypes tests
1368     if (input.GetDataType()               == armnn::DataType::QAsymmS8 &&
1369         previousOutputIn.GetDataType()    == armnn::DataType::QAsymmS8 &&
1370         previousCellStateIn.GetDataType() == armnn::DataType::QSymmS16 &&
1371         outputStateOut.GetDataType()      == armnn::DataType::QAsymmS8 &&
1372         cellStateOut.GetDataType()        == armnn::DataType::QSymmS16 &&
1373         output.GetDataType()              == armnn::DataType::QAsymmS8)
1374     {
1375         FORWARD_WORKLOAD_VALIDATE_FUNC(NeonQLstmWorkloadValidate,
1376                                        reasonIfUnsupported,
1377                                        input,
1378                                        previousCellStateIn,
1379                                        previousOutputIn,
1380                                        cellStateOut,
1381                                        outputStateOut,
1382                                        output,
1383                                        descriptor,
1384                                        paramsInfo);
1385     }
1386     else
1387     {
1388         return false;
1389     }
1390 }
1391 
IsQuantizeSupported(const TensorInfo & input,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1392 bool NeonLayerSupport::IsQuantizeSupported(const TensorInfo& input,
1393                                            const TensorInfo& output,
1394                                            Optional<std::string&> reasonIfUnsupported) const
1395 {
1396     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonQuantizeWorkloadValidate,
1397                                    reasonIfUnsupported,
1398                                    input,
1399                                    output);
1400 }
1401 
IsQuantizedLstmSupported(const TensorInfo & input,const TensorInfo & cellStateIn,const TensorInfo & outputStateIn,const TensorInfo & cellStateOut,const TensorInfo & outputStateOut,const QuantizedLstmInputParamsInfo & paramsInfo,Optional<std::string &> reasonIfUnsupported) const1402 bool NeonLayerSupport::IsQuantizedLstmSupported(const TensorInfo& input,
1403                                                 const TensorInfo& cellStateIn,
1404                                                 const TensorInfo& outputStateIn,
1405                                                 const TensorInfo& cellStateOut,
1406                                                 const TensorInfo& outputStateOut,
1407                                                 const QuantizedLstmInputParamsInfo& paramsInfo,
1408                                                 Optional<std::string&> reasonIfUnsupported) const
1409 {
1410     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonQuantizedLstmWorkloadValidate,
1411                                    reasonIfUnsupported,
1412                                    input,
1413                                    cellStateIn,
1414                                    outputStateIn,
1415                                    cellStateOut,
1416                                    outputStateOut,
1417                                    paramsInfo);
1418 }
1419 
IsReduceSupported(const TensorInfo & input,const TensorInfo & output,const ReduceDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1420 bool NeonLayerSupport::IsReduceSupported(const TensorInfo& input,
1421                                          const TensorInfo& output,
1422                                          const ReduceDescriptor& descriptor,
1423                                          Optional<std::string&> reasonIfUnsupported) const
1424 {
1425     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonReduceWorkloadValidate,
1426                                    reasonIfUnsupported,
1427                                    input,
1428                                    output,
1429                                    descriptor);
1430 }
1431 
IsReshapeSupported(const TensorInfo & input,const TensorInfo & output,const ReshapeDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1432 bool NeonLayerSupport::IsReshapeSupported(const TensorInfo& input,
1433                                           const TensorInfo& output,
1434                                           const ReshapeDescriptor& descriptor,
1435                                           Optional<std::string&> reasonIfUnsupported) const
1436 {
1437     armnn::IgnoreUnused(descriptor);
1438     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonReshapeWorkloadValidate,
1439                                    reasonIfUnsupported,
1440                                    input,
1441                                    output);
1442 }
1443 
IsResizeSupported(const TensorInfo & input,const TensorInfo & output,const ResizeDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1444 bool NeonLayerSupport::IsResizeSupported(const TensorInfo& input,
1445                                          const TensorInfo& output,
1446                                          const ResizeDescriptor& descriptor,
1447                                          Optional<std::string&> reasonIfUnsupported) const
1448 {
1449     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonResizeWorkloadValidate,
1450                                    reasonIfUnsupported,
1451                                    input,
1452                                    output,
1453                                    descriptor);
1454 }
1455 
IsSliceSupported(const TensorInfo & input,const TensorInfo & output,const SliceDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1456 bool NeonLayerSupport::IsSliceSupported(const TensorInfo& input,
1457                                         const TensorInfo& output,
1458                                         const SliceDescriptor& descriptor,
1459                                         Optional<std::string&> reasonIfUnsupported) const
1460 {
1461     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSliceWorkloadValidate,
1462                                    reasonIfUnsupported,
1463                                    input,
1464                                    output,
1465                                    descriptor);
1466 }
1467 
IsSoftmaxSupported(const TensorInfo & input,const TensorInfo & output,const SoftmaxDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1468 bool NeonLayerSupport::IsSoftmaxSupported(const TensorInfo& input,
1469                                           const TensorInfo& output,
1470                                           const SoftmaxDescriptor& descriptor,
1471                                           Optional<std::string&> reasonIfUnsupported) const
1472 {
1473     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSoftmaxWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1474 }
1475 
IsSpaceToBatchNdSupported(const TensorInfo & input,const TensorInfo & output,const SpaceToBatchNdDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1476 bool NeonLayerSupport::IsSpaceToBatchNdSupported(const TensorInfo& input,
1477                                                  const TensorInfo& output,
1478                                                  const SpaceToBatchNdDescriptor& descriptor,
1479                                                  Optional<std::string&> reasonIfUnsupported) const
1480 {
1481     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSpaceToBatchNdWorkloadValidate,
1482                                    reasonIfUnsupported,
1483                                    input,
1484                                    output,
1485                                    descriptor);
1486 }
1487 
IsSpaceToDepthSupported(const TensorInfo & input,const TensorInfo & output,const SpaceToDepthDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1488 bool NeonLayerSupport::IsSpaceToDepthSupported(const TensorInfo& input,
1489                                                const TensorInfo& output,
1490                                                const SpaceToDepthDescriptor& descriptor,
1491                                                Optional<std::string&> reasonIfUnsupported) const
1492 {
1493     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSpaceToDepthWorkloadValidate,
1494                                    reasonIfUnsupported,
1495                                    input,
1496                                    output,
1497                                    descriptor);
1498 }
1499 
IsSplitterSupported(const TensorInfo & input,const std::vector<std::reference_wrapper<TensorInfo>> & outputs,const ViewsDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1500 bool NeonLayerSupport::IsSplitterSupported(const TensorInfo& input,
1501                                            const std::vector<std::reference_wrapper<TensorInfo>>& outputs,
1502                                            const ViewsDescriptor& descriptor,
1503                                            Optional<std::string&> reasonIfUnsupported) const
1504 {
1505 #if defined(ARMCOMPUTENEON_ENABLED)
1506     // Split along the last dimension, cannot use sub-tensors
1507     // as width and height of the sub-tensors do not match
1508     // the width and height of the parent tensor
1509     // in case of input with more than 2D.
1510     std::set<unsigned int> splitAxis = ComputeSplitAxis(descriptor, input.GetShape());
1511     if (descriptor.GetNumDimensions() > 2 && splitAxis.size() == 1 &&
1512         *splitAxis.begin() == descriptor.GetNumDimensions() - 1 )
1513     {
1514         FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSplitterWorkloadValidate,
1515                                        reasonIfUnsupported,
1516                                        input,
1517                                        outputs,
1518                                        *splitAxis.begin());
1519     }
1520 #endif
1521     IgnoreUnused(descriptor);
1522     for (auto output : outputs)
1523     {
1524         if (!input.IsTypeSpaceMatch(output)) // Cannot use sub-tensors if the types are not same space
1525         {
1526             SetValueChecked(reasonIfUnsupported, "Neon Splitter: Types and quantization parameters must match.");
1527             return false;
1528         }
1529     }
1530     return true;
1531 }
1532 
IsStackSupported(const std::vector<const TensorInfo * > & inputs,const TensorInfo & output,const StackDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1533 bool NeonLayerSupport::IsStackSupported(const std::vector<const TensorInfo*>& inputs,
1534                                         const TensorInfo& output,
1535                                         const StackDescriptor& descriptor,
1536                                         Optional<std::string&> reasonIfUnsupported) const
1537 {
1538     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonStackWorkloadValidate,
1539                                    reasonIfUnsupported,
1540                                    inputs,
1541                                    output,
1542                                    descriptor);
1543 }
1544 
IsStridedSliceSupported(const TensorInfo & input,const TensorInfo & output,const StridedSliceDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1545 bool NeonLayerSupport::IsStridedSliceSupported(const TensorInfo& input,
1546                                                const TensorInfo& output,
1547                                                const StridedSliceDescriptor& descriptor,
1548                                                Optional<std::string&> reasonIfUnsupported) const
1549 {
1550     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonStridedSliceWorkloadValidate,
1551                                    reasonIfUnsupported,
1552                                    input,
1553                                    output,
1554                                    descriptor);
1555 }
1556 
IsSubtractionSupported(const TensorInfo & input0,const TensorInfo & input1,const TensorInfo & output,Optional<std::string &> reasonIfUnsupported) const1557 bool NeonLayerSupport::IsSubtractionSupported(const TensorInfo& input0,
1558                                               const TensorInfo& input1,
1559                                               const TensorInfo& output,
1560                                               Optional<std::string&> reasonIfUnsupported) const
1561 {
1562     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonSubtractionWorkloadValidate,
1563                                    reasonIfUnsupported,
1564                                    input0,
1565                                    input1,
1566                                    output,
1567                                    nullptr);
1568 }
1569 
IsTransposeConvolution2dSupported(const TensorInfo & input,const TensorInfo & output,const TransposeConvolution2dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,Optional<std::string &> reasonIfUnsupported) const1570 bool NeonLayerSupport::IsTransposeConvolution2dSupported(const TensorInfo& input,
1571                                                          const TensorInfo& output,
1572                                                          const TransposeConvolution2dDescriptor& descriptor,
1573                                                          const TensorInfo& weights,
1574                                                          const Optional<TensorInfo>& biases,
1575                                                          Optional<std::string&> reasonIfUnsupported) const
1576 {
1577     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonTransposeConvolution2dWorkloadValidate,
1578                                    reasonIfUnsupported,
1579                                    input,
1580                                    output,
1581                                    descriptor,
1582                                    weights,
1583                                    biases);
1584 }
1585 
IsTransposeSupported(const TensorInfo & input,const TensorInfo & output,const TransposeDescriptor & descriptor,Optional<std::string &> reasonIfUnsupported) const1586 bool NeonLayerSupport::IsTransposeSupported(const TensorInfo& input,
1587                                             const TensorInfo& output,
1588                                             const TransposeDescriptor& descriptor,
1589                                             Optional<std::string&> reasonIfUnsupported) const
1590 {
1591     FORWARD_WORKLOAD_VALIDATE_FUNC(NeonTransposeWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
1592 }
1593 
IsUnidirectionalSequenceLstmSupported(const TensorInfo & input,const TensorInfo & outputStateIn,const TensorInfo & cellStateIn,const TensorInfo & outputStateOut,const TensorInfo & cellStateOut,const TensorInfo & output,const UnidirectionalSequenceLstmDescriptor & descriptor,const LstmInputParamsInfo & paramsInfo,Optional<std::string &> reasonIfUnsupported) const1594 bool NeonLayerSupport::IsUnidirectionalSequenceLstmSupported(const TensorInfo& input,
1595                                                              const TensorInfo& outputStateIn,
1596                                                              const TensorInfo& cellStateIn,
1597                                                              const TensorInfo& outputStateOut,
1598                                                              const TensorInfo& cellStateOut,
1599                                                              const TensorInfo& output,
1600                                                              const UnidirectionalSequenceLstmDescriptor& descriptor,
1601                                                              const LstmInputParamsInfo& paramsInfo,
1602                                                              Optional<std::string&> reasonIfUnsupported) const
1603 {
1604     if (input.GetDataType() == armnn::DataType::QAsymmS8 &&
1605         outputStateIn.GetDataType() == armnn::DataType::QAsymmS8 &&
1606         cellStateIn.GetDataType() == armnn::DataType::QSymmS16 &&
1607         outputStateOut.GetDataType() == armnn::DataType::QAsymmS8 &&
1608         cellStateOut.GetDataType() == armnn::DataType::QSymmS16 &&
1609         output.GetDataType() == armnn::DataType::QAsymmS8)
1610     {
1611         FORWARD_WORKLOAD_VALIDATE_FUNC(NeonUnidirectionalSequenceLstmWorkloadValidate,
1612                                        reasonIfUnsupported,
1613                                        input,
1614                                        outputStateIn,
1615                                        cellStateIn,
1616                                        outputStateOut,
1617                                        cellStateOut,
1618                                        output,
1619                                        descriptor,
1620                                        paramsInfo);
1621     }
1622     else
1623     {
1624         FORWARD_WORKLOAD_VALIDATE_FUNC(NeonUnidirectionalSequenceLstmFloatWorkloadValidate,
1625                                        reasonIfUnsupported,
1626                                        input,
1627                                        outputStateIn,
1628                                        cellStateIn,
1629                                        outputStateOut,
1630                                        cellStateOut,
1631                                        output,
1632                                        descriptor,
1633                                        paramsInfo);
1634     }
1635 }
1636 
1637 } // namespace armnn
1638