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