blob: 3ca8bb5c46ea8bead6bc3d3d7237d7889f669d2b [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5
telsoa014fcda012018-03-09 14:13:49 +00006#include "ClLayerSupport.hpp"
David Beck3e9e1152018-10-17 14:17:50 +01007#include "ClBackendId.hpp"
arovir017c22c702018-10-09 11:16:46 +01008
David Beck3cc9a622018-10-12 10:38:31 +01009#include <armnn/Descriptors.hpp>
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +010010#include <armnn/InternalTypes.hpp>
11#include <armnn/LayerSupportCommon.hpp>
telsoa014fcda012018-03-09 14:13:49 +000012
David Beck3e9e1152018-10-17 14:17:50 +010013#include <backends/LayerSupportRegistry.hpp>
14
telsoa014fcda012018-03-09 14:13:49 +000015#include <boost/core/ignore_unused.hpp>
16
17#ifdef ARMCOMPUTECL_ENABLED
David Beckac42efd2018-09-26 17:41:13 +010018#include "workloads/ClAdditionWorkload.hpp"
Nattapat Chaimanowonge06757e2018-10-11 15:39:18 +010019#include "workloads/ClActivationWorkload.hpp"
David Beckac42efd2018-09-26 17:41:13 +010020#include "workloads/ClBatchNormalizationFloatWorkload.hpp"
21#include "workloads/ClConvertFp16ToFp32Workload.hpp"
22#include "workloads/ClConvertFp32ToFp16Workload.hpp"
Matthew Benthamd8067922018-10-03 17:18:04 +010023#include "workloads/ClConvolution2dWorkload.hpp"
Matthew Benthamd8777392018-10-08 09:38:55 +010024#include "workloads/ClDepthwiseConvolutionWorkload.hpp"
David Beckac42efd2018-09-26 17:41:13 +010025#include "workloads/ClDivisionFloatWorkload.hpp"
David Beckac42efd2018-09-26 17:41:13 +010026#include "workloads/ClFullyConnectedWorkload.hpp"
arovir01085f0a42018-10-08 14:48:19 +010027#include "workloads/ClL2NormalizationFloatWorkload.hpp"
28#include "workloads/ClLstmFloatWorkload.hpp"
29#include "workloads/ClMultiplicationWorkload.hpp"
David Beckac42efd2018-09-26 17:41:13 +010030#include "workloads/ClNormalizationFloatWorkload.hpp"
arovir01085f0a42018-10-08 14:48:19 +010031#include "workloads/ClPadWorkload.hpp"
32#include "workloads/ClPermuteWorkload.hpp"
Nattapat Chaimanowongac9e0962018-10-10 17:18:35 +010033#include "workloads/ClPooling2dWorkload.hpp"
David Beckac42efd2018-09-26 17:41:13 +010034#include "workloads/ClSoftmaxBaseWorkload.hpp"
35#include "workloads/ClSubtractionWorkload.hpp"
telsoa014fcda012018-03-09 14:13:49 +000036#endif
37
38using namespace boost;
39
40namespace armnn
41{
arovir017c22c702018-10-09 11:16:46 +010042
telsoa014fcda012018-03-09 14:13:49 +000043namespace
44{
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +010045
David Beck3e9e1152018-10-17 14:17:50 +010046ILayerSupportSharedPtr GetLayerSupportPointer()
47{
48 static ILayerSupportSharedPtr instance{new ClLayerSupport};
49 return instance;
50}
51
52static StaticRegistryInitializer<LayerSupportRegistry> g_RegisterHelper{
53 LayerSupportRegistryInstance(),
54 ClBackendId(),
55 []()
56 {
57 return GetLayerSupportPointer();
58 }
59};
60
telsoa014fcda012018-03-09 14:13:49 +000061template<unsigned int FilterSize>
62bool IsMatchingSize2d(const TensorInfo& weightInfo)
63{
telsoa01c577f2c2018-08-31 09:22:23 +010064 // Width & Height must match.
telsoa014fcda012018-03-09 14:13:49 +000065 return (weightInfo.GetShape()[3] == FilterSize) && (weightInfo.GetShape()[2] == FilterSize);
66}
67
68template<uint32_t ValidStride>
69bool IsMatchingStride(uint32_t actualStride)
70{
71 return ValidStride == actualStride;
72}
73
74template<uint32_t FirstStride, uint32_t SecondStride, uint32_t... ValidStrides>
75bool IsMatchingStride(uint32_t actualStride)
76{
77 return IsMatchingStride<FirstStride>(actualStride) || IsMatchingStride<SecondStride, ValidStrides...>(actualStride);
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +010078}
telsoa014fcda012018-03-09 14:13:49 +000079
arovir01085f0a42018-10-08 14:48:19 +010080bool IsClBackendSupported(Optional<std::string&> reasonIfUnsupported)
telsoa014fcda012018-03-09 14:13:49 +000081{
82#if ARMCOMPUTECL_ENABLED
83 return true;
84#else
arovir01085f0a42018-10-08 14:48:19 +010085 if (reasonIfUnsupported)
telsoa014fcda012018-03-09 14:13:49 +000086 {
arovir01085f0a42018-10-08 14:48:19 +010087 reasonIfUnsupported.value() = "The armnn library has been built without CL support";
telsoa014fcda012018-03-09 14:13:49 +000088 }
89 return false;
90#endif
91}
92
93#if ARMCOMPUTECL_ENABLED
94#define FORWARD_CL_LAYER_SUPPORT_FUNC(expr) (expr)
95#else
96#define FORWARD_CL_LAYER_SUPPORT_FUNC(expr) IsClBackendSupported(reasonIfUnsupported)
97#endif
98
99#if ARMCOMPUTECL_ENABLED
100template<class FuncType, class... Args>
arovir01085f0a42018-10-08 14:48:19 +0100101inline bool IsWorkloadSupported(FuncType&& func, Optional<std::string&> reasonIfUnsupported, Args&&... args)
telsoa014fcda012018-03-09 14:13:49 +0000102{
103 arm_compute::Status aclStatus = func(std::forward<Args>(args)...);
104 const bool supported = (aclStatus.error_code() == arm_compute::ErrorCode::OK);
105 if (!supported && reasonIfUnsupported)
106 {
arovir01085f0a42018-10-08 14:48:19 +0100107 reasonIfUnsupported.value() = aclStatus.error_description();
telsoa014fcda012018-03-09 14:13:49 +0000108 }
109 return supported;
110}
111
112#define FORWARD_WORKLOAD_VALIDATE_FUNC(func, reasonIfUnsupported, ...) \
113 return IsWorkloadSupported(func, reasonIfUnsupported, __VA_ARGS__);
114#else
115#define FORWARD_WORKLOAD_VALIDATE_FUNC(func, reasonIfUnsupported, ...) \
116 return IsClBackendSupported(reasonIfUnsupported);
117#endif
118
telsoa01c577f2c2018-08-31 09:22:23 +0100119template<typename FloatFunc, typename Uint8Func, typename ... Params>
arovir01085f0a42018-10-08 14:48:19 +0100120bool IsSupportedForDataTypeCl(Optional<std::string&> reasonIfUnsupported,
telsoa014fcda012018-03-09 14:13:49 +0000121 DataType dataType,
telsoa01c577f2c2018-08-31 09:22:23 +0100122 FloatFunc floatFuncPtr,
telsoa014fcda012018-03-09 14:13:49 +0000123 Uint8Func uint8FuncPtr,
124 Params&&... params)
125{
126 return IsClBackendSupported(reasonIfUnsupported) &&
127 IsSupportedForDataTypeGeneric(reasonIfUnsupported,
128 dataType,
129 floatFuncPtr,
telsoa01c577f2c2018-08-31 09:22:23 +0100130 floatFuncPtr,
telsoa014fcda012018-03-09 14:13:49 +0000131 uint8FuncPtr,
132 std::forward<Params>(params)...);
133}
134
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100135} // anonymous namespace
136
137bool ClLayerSupport::IsActivationSupported(const TensorInfo& input,
138 const TensorInfo& output,
139 const ActivationDescriptor& descriptor,
140 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000141{
telsoa01c577f2c2018-08-31 09:22:23 +0100142 FORWARD_WORKLOAD_VALIDATE_FUNC(ClActivationWorkloadValidate,
143 reasonIfUnsupported,
144 input,
145 output,
146 descriptor);
telsoa014fcda012018-03-09 14:13:49 +0000147}
148
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100149bool ClLayerSupport::IsAdditionSupported(const TensorInfo& input0,
150 const TensorInfo& input1,
151 const TensorInfo& output,
152 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000153{
arovir01085f0a42018-10-08 14:48:19 +0100154 FORWARD_WORKLOAD_VALIDATE_FUNC(ClAdditionValidate,
155 reasonIfUnsupported,
156 input0,
157 input1,
158 output);
telsoa014fcda012018-03-09 14:13:49 +0000159}
160
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100161bool ClLayerSupport::IsBatchNormalizationSupported(const TensorInfo& input,
162 const TensorInfo& output,
163 const TensorInfo& mean,
164 const TensorInfo& var,
165 const TensorInfo& beta,
166 const TensorInfo& gamma,
167 const BatchNormalizationDescriptor& descriptor,
168 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000169{
telsoa01c577f2c2018-08-31 09:22:23 +0100170 FORWARD_WORKLOAD_VALIDATE_FUNC(ClBatchNormalizationValidate,
171 reasonIfUnsupported,
172 input,
173 output,
174 mean,
175 var,
176 beta,
177 gamma,
178 descriptor);
telsoa014fcda012018-03-09 14:13:49 +0000179}
180
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100181bool ClLayerSupport::IsConstantSupported(const TensorInfo& output,
182 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000183{
184 return IsSupportedForDataTypeCl(reasonIfUnsupported,
185 output.GetDataType(),
186 &TrueFunc<>,
187 &FalseFuncU8<>);
188}
189
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100190bool ClLayerSupport::IsConvertFp16ToFp32Supported(const TensorInfo& input,
191 const TensorInfo& output,
192 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000193{
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100194 FORWARD_WORKLOAD_VALIDATE_FUNC(ClConvertFp16ToFp32WorkloadValidate,
195 reasonIfUnsupported,
196 input,
197 output);
telsoa014fcda012018-03-09 14:13:49 +0000198}
199
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100200bool ClLayerSupport::IsConvertFp32ToFp16Supported(const TensorInfo& input,
201 const TensorInfo& output,
202 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000203{
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100204 FORWARD_WORKLOAD_VALIDATE_FUNC(ClConvertFp32ToFp16WorkloadValidate,
205 reasonIfUnsupported,
206 input,
207 output);
telsoa014fcda012018-03-09 14:13:49 +0000208}
209
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100210bool ClLayerSupport::IsConvolution2dSupported(const TensorInfo& input,
211 const TensorInfo& output,
212 const Convolution2dDescriptor& descriptor,
213 const TensorInfo& weights,
214 const Optional<TensorInfo>& biases,
215 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000216{
surmeh013537c2c2018-05-18 16:31:43 +0100217 FORWARD_WORKLOAD_VALIDATE_FUNC(ClConvolution2dWorkloadValidate,
218 reasonIfUnsupported,
219 input,
220 output,
221 descriptor,
222 weights,
223 biases);
telsoa014fcda012018-03-09 14:13:49 +0000224}
225
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100226bool ClLayerSupport::IsDepthwiseConvolutionSupported(const TensorInfo& input,
227 const TensorInfo& output,
228 const DepthwiseConvolution2dDescriptor& descriptor,
229 const TensorInfo& weights,
230 const Optional<TensorInfo>& biases,
231 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000232{
telsoa01c577f2c2018-08-31 09:22:23 +0100233 FORWARD_WORKLOAD_VALIDATE_FUNC(ClDepthwiseConvolutionWorkloadValidate,
234 reasonIfUnsupported,
235 input,
236 output,
237 descriptor,
238 weights,
239 biases);
telsoa014fcda012018-03-09 14:13:49 +0000240}
241
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100242bool ClLayerSupport::IsDivisionSupported(const TensorInfo& input0,
243 const TensorInfo& input1,
244 const TensorInfo& output,
245 Optional<std::string&> reasonIfUnsupported) const
Francis Murtaghe7a86a42018-08-29 12:42:10 +0100246{
247 FORWARD_WORKLOAD_VALIDATE_FUNC(ClDivisionWorkloadValidate,
248 reasonIfUnsupported,
249 input0,
250 input1,
251 output);
252}
253
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100254bool ClLayerSupport::IsFakeQuantizationSupported(const TensorInfo& input,
255 const FakeQuantizationDescriptor& descriptor,
256 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000257{
258 ignore_unused(input);
259 ignore_unused(descriptor);
arovir01085f0a42018-10-08 14:48:19 +0100260 ignore_unused(reasonIfUnsupported);
telsoa014fcda012018-03-09 14:13:49 +0000261 return false;
262}
263
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100264bool ClLayerSupport::IsFloorSupported(const TensorInfo& input,
265 const TensorInfo& output,
266 Optional<std::string&> reasonIfUnsupported) const
telsoa014fcda012018-03-09 14:13:49 +0000267{
268 ignore_unused(output);
telsoa01c577f2c2018-08-31 09:22:23 +0100269 return IsClBackendSupported(reasonIfUnsupported) &&
270 IsSupportedForDataTypeGeneric(reasonIfUnsupported,
271 input.GetDataType(),
272 &FalseFuncF16<>,
273 &TrueFunc<>,
274 &FalseFuncU8<>);
275}
276
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100277bool ClLayerSupport::IsFullyConnectedSupported(const TensorInfo& input,
278 const TensorInfo& output,
279 const TensorInfo& weights,
280 const TensorInfo& biases,
281 const FullyConnectedDescriptor& descriptor,
282 Optional<std::string&> reasonIfUnsupported) const
283{
284 FORWARD_WORKLOAD_VALIDATE_FUNC(ClFullyConnectedWorkloadValidate,
285 reasonIfUnsupported,
286 input,
287 output,
288 weights,
289 biases,
290 descriptor);
291}
292
293bool ClLayerSupport::IsInputSupported(const TensorInfo& input,
294 Optional<std::string&> reasonIfUnsupported) const
295{
296 return IsSupportedForDataTypeCl(reasonIfUnsupported,
297 input.GetDataType(),
298 &TrueFunc<>,
299 &TrueFunc<>);
300}
301
302bool ClLayerSupport::IsL2NormalizationSupported(const TensorInfo& input,
303 const TensorInfo& output,
304 const L2NormalizationDescriptor& descriptor,
305 Optional<std::string&> reasonIfUnsupported) const
306{
307 FORWARD_WORKLOAD_VALIDATE_FUNC(ClL2NormalizationWorkloadValidate,
308 reasonIfUnsupported,
309 input,
310 output,
311 descriptor);
312}
313
314bool ClLayerSupport::IsLstmSupported(const TensorInfo& input,
315 const TensorInfo& outputStateIn,
316 const TensorInfo& cellStateIn,
317 const TensorInfo& scratchBuffer,
318 const TensorInfo& outputStateOut,
319 const TensorInfo& cellStateOut,
320 const TensorInfo& output,
321 const LstmDescriptor& descriptor,
322 const TensorInfo& inputToForgetWeights,
323 const TensorInfo& inputToCellWeights,
324 const TensorInfo& inputToOutputWeights,
325 const TensorInfo& recurrentToForgetWeights,
326 const TensorInfo& recurrentToCellWeights,
327 const TensorInfo& recurrentToOutputWeights,
328 const TensorInfo& forgetGateBias,
329 const TensorInfo& cellBias,
330 const TensorInfo& outputGateBias,
331 const TensorInfo* inputToInputWeights,
332 const TensorInfo* recurrentToInputWeights,
333 const TensorInfo* cellToInputWeights,
334 const TensorInfo* inputGateBias,
335 const TensorInfo* projectionWeights,
336 const TensorInfo* projectionBias,
337 const TensorInfo* cellToForgetWeights,
338 const TensorInfo* cellToOutputWeights,
339 Optional<std::string&> reasonIfUnsupported) const
telsoa01c577f2c2018-08-31 09:22:23 +0100340{
arovir01085f0a42018-10-08 14:48:19 +0100341 FORWARD_WORKLOAD_VALIDATE_FUNC(ClLstmFloatWorkloadValidate,
342 reasonIfUnsupported,
343 input,
344 outputStateIn,
345 cellStateIn,
346 scratchBuffer,
347 outputStateOut,
348 cellStateOut,
349 output,
350 descriptor,
351 inputToForgetWeights,
352 inputToCellWeights,
353 inputToOutputWeights,
354 recurrentToForgetWeights,
355 recurrentToCellWeights,
356 recurrentToOutputWeights,
357 forgetGateBias,
358 cellBias,
359 outputGateBias,
360 inputToInputWeights,
361 recurrentToInputWeights,
362 cellToInputWeights,
363 inputGateBias,
364 projectionWeights,
365 projectionBias,
366 cellToForgetWeights,
367 cellToOutputWeights);
telsoa01c577f2c2018-08-31 09:22:23 +0100368}
369
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100370bool ClLayerSupport::IsMeanSupported(const TensorInfo& input,
371 const TensorInfo& output,
372 const MeanDescriptor& descriptor,
373 Optional<std::string&> reasonIfUnsupported) const
narpra0132b90462018-09-13 11:07:48 +0100374{
arovir01085f0a42018-10-08 14:48:19 +0100375 ignore_unused(input);
376 ignore_unused(output);
377 ignore_unused(descriptor);
378 ignore_unused(reasonIfUnsupported);
narpra0132b90462018-09-13 11:07:48 +0100379 return false;
380}
381
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100382bool ClLayerSupport::IsMergerSupported(const std::vector<const TensorInfo*> inputs,
383 const OriginsDescriptor& descriptor,
384 Optional<std::string&> reasonIfUnsupported) const
385{
386 ignore_unused(descriptor);
387 return IsSupportedForDataTypeCl(reasonIfUnsupported,
388 inputs[0]->GetDataType(),
389 &TrueFunc<>,
390 &FalseFuncU8<>);
391}
392
393bool ClLayerSupport::IsMultiplicationSupported(const TensorInfo& input0,
394 const TensorInfo& input1,
395 const TensorInfo& output,
396 Optional<std::string&> reasonIfUnsupported) const
397{
398 FORWARD_WORKLOAD_VALIDATE_FUNC(ClMultiplicationWorkloadValidate,
399 reasonIfUnsupported,
400 input0,
401 input1,
402 output);
403}
404
405bool ClLayerSupport::IsNormalizationSupported(const TensorInfo& input,
406 const TensorInfo& output,
407 const NormalizationDescriptor& descriptor,
408 Optional<std::string&> reasonIfUnsupported) const
409{
410 FORWARD_WORKLOAD_VALIDATE_FUNC(ClNormalizationWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
411}
412
413bool ClLayerSupport::IsOutputSupported(const TensorInfo& output,
414 Optional<std::string&> reasonIfUnsupported) const
415{
416 return IsSupportedForDataTypeCl(reasonIfUnsupported,
417 output.GetDataType(),
418 &TrueFunc<>,
419 &TrueFunc<>);
420}
421
422bool ClLayerSupport::IsPadSupported(const TensorInfo& input,
423 const TensorInfo& output,
424 const PadDescriptor& descriptor,
425 Optional<std::string&> reasonIfUnsupported) const
arovir01085f0a42018-10-08 14:48:19 +0100426{
427 FORWARD_WORKLOAD_VALIDATE_FUNC(ClPadValidate,
428 reasonIfUnsupported,
429 input,
430 output,
431 descriptor);
432}
433
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100434bool ClLayerSupport::IsPermuteSupported(const TensorInfo& input,
435 const TensorInfo& output,
436 const PermuteDescriptor& descriptor,
437 Optional<std::string&> reasonIfUnsupported) const
438{
439 ignore_unused(input);
440 ignore_unused(output);
441 FORWARD_WORKLOAD_VALIDATE_FUNC(ClPermuteWorkloadValidate, reasonIfUnsupported, descriptor);
telsoa014fcda012018-03-09 14:13:49 +0000442}
Aron Virginas-Tarbcf9f162018-10-15 11:47:37 +0100443
444bool ClLayerSupport::IsPooling2dSupported(const TensorInfo& input,
445 const TensorInfo& output,
446 const Pooling2dDescriptor& descriptor,
447 Optional<std::string&> reasonIfUnsupported) const
448{
449 FORWARD_WORKLOAD_VALIDATE_FUNC(ClPooling2dWorkloadValidate, reasonIfUnsupported, input, output, descriptor);
450}
451
452bool ClLayerSupport::IsReshapeSupported(const TensorInfo& input,
453 Optional<std::string&> reasonIfUnsupported) const
454{
455 ignore_unused(input);
456 ignore_unused(reasonIfUnsupported);
457 return true;
458}
459
460bool ClLayerSupport::IsResizeBilinearSupported(const TensorInfo& input,
461 Optional<std::string&> reasonIfUnsupported) const
462{
463 return IsSupportedForDataTypeCl(reasonIfUnsupported,
464 input.GetDataType(),
465 &TrueFunc<>,
466 &FalseFuncU8<>);
467}
468
469bool ClLayerSupport::IsSoftmaxSupported(const TensorInfo& input,
470 const TensorInfo& output,
471 const SoftmaxDescriptor& descriptor,
472 Optional<std::string&> reasonIfUnsupported) const
473{
474 ignore_unused(descriptor);
475 FORWARD_WORKLOAD_VALIDATE_FUNC(ClSoftmaxWorkloadValidate, reasonIfUnsupported, input, output);
476}
477
478bool ClLayerSupport::IsSplitterSupported(const TensorInfo& input,
479 const ViewsDescriptor& descriptor,
480 Optional<std::string&> reasonIfUnsupported) const
481{
482 ignore_unused(descriptor);
483 return IsSupportedForDataTypeCl(reasonIfUnsupported,
484 input.GetDataType(),
485 &TrueFunc<>,
486 &TrueFunc<>);
487}
488
489bool ClLayerSupport::IsSubtractionSupported(const TensorInfo& input0,
490 const TensorInfo& input1,
491 const TensorInfo& output,
492 Optional<std::string&> reasonIfUnsupported) const
493{
494 FORWARD_WORKLOAD_VALIDATE_FUNC(ClSubtractionValidate,
495 reasonIfUnsupported,
496 input0,
497 input1,
498 output);
499}
500
501} // namespace armnn