blob: 6ad68164749ba34e1cc2de0040f83ffdead36a43 [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 "RefLayerSupport.hpp"
David Beck3e9e1152018-10-17 14:17:50 +01007#include "RefBackendId.hpp"
David Beck3cc9a622018-10-12 10:38:31 +01008
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +00009#include <InternalTypes.hpp>
10#include <LayerSupportCommon.hpp>
telsoa014fcda012018-03-09 14:13:49 +000011#include <armnn/Types.hpp>
Derek Lamberti50db4e82019-03-13 14:16:15 +000012#include <armnn/Descriptors.hpp>
telsoa014fcda012018-03-09 14:13:49 +000013
David Beck111b5d92018-11-12 14:59:37 +000014#include <backendsCommon/BackendRegistry.hpp>
David Beck3e9e1152018-10-17 14:17:50 +010015
telsoa014fcda012018-03-09 14:13:49 +000016#include <boost/core/ignore_unused.hpp>
telsoa014fcda012018-03-09 14:13:49 +000017
Derek Lamberti50db4e82019-03-13 14:16:15 +000018#include <vector>
19#include <algorithm>
20#include <array>
21
telsoa014fcda012018-03-09 14:13:49 +000022using namespace boost;
23
24namespace armnn
25{
26
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +010027namespace
28{
29
30template<typename Float32Func, typename Uint8Func, typename ... Params>
31bool IsSupportedForDataTypeRef(Optional<std::string&> reasonIfUnsupported,
32 DataType dataType,
33 Float32Func floatFuncPtr,
34 Uint8Func uint8FuncPtr,
35 Params&&... params)
36{
37 return IsSupportedForDataTypeGeneric(reasonIfUnsupported,
38 dataType,
39 &FalseFunc<Params...>,
40 floatFuncPtr,
41 uint8FuncPtr,
narpra01db2b1602019-01-23 15:23:11 +000042 &FalseFunc<Params...>,
kevmay012b4d88e2019-01-24 14:05:09 +000043 &FalseFunc<Params...>,
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +010044 std::forward<Params>(params)...);
45}
46
47} // anonymous namespace
48
Derek Lamberti50db4e82019-03-13 14:16:15 +000049
50namespace
51{
52template<typename F>
53bool CheckSupportRule(F rule, Optional<std::string&> reasonIfUnsupported, const char* reason)
54{
55 bool supported = rule();
56 if (!supported && reason)
57 {
58 reasonIfUnsupported.value() += std::string(reason) + "\n"; // Append the reason on a new line
59 }
60 return supported;
61}
62
63struct Rule
64{
65 bool operator()() const
66 {
67 return m_Res;
68 }
69
70 bool m_Res = true;
71};
72
Derek Lamberti2a434a82019-03-20 13:07:57 +000073template<typename T>
74bool AllTypesAreEqualImpl(T t)
Derek Lamberti50db4e82019-03-13 14:16:15 +000075{
76 return true;
77}
78
79template<typename T, typename... Rest>
80bool AllTypesAreEqualImpl(T t1, T t2, Rest... rest)
81{
82 static_assert(std::is_same<T, TensorInfo>::value, "Type T must be a TensorInfo");
83
Derek Lamberti2a434a82019-03-20 13:07:57 +000084 return (t1.GetDataType() == t2.GetDataType()) && AllTypesAreEqualImpl(t2, rest...);
Derek Lamberti50db4e82019-03-13 14:16:15 +000085}
86
87struct TypesAreEqual : public Rule
88{
89 template<typename ... Ts>
90 TypesAreEqual(const Ts&... ts)
91 {
92 m_Res = AllTypesAreEqualImpl(ts...);
93 }
94};
95
96struct QuantizationParametersAreEqual : public Rule
97{
98 QuantizationParametersAreEqual(const TensorInfo& info0, const TensorInfo& info1)
99 {
100 m_Res = info0.GetQuantizationScale() == info1.GetQuantizationScale() &&
101 info0.GetQuantizationOffset() == info1.GetQuantizationOffset();
102 }
103};
104
105struct TypeAnyOf : public Rule
106{
107 template<typename Container>
108 TypeAnyOf(const TensorInfo& info, const Container& c)
109 {
110 m_Res = std::any_of(c.begin(), c.end(), [&info](DataType dt)
111 {
112 return dt == info.GetDataType();
113 });
114 }
115};
116
117struct ShapesAreSameRank : public Rule
118{
119 ShapesAreSameRank(const TensorInfo& info0, const TensorInfo& info1)
120 {
121 m_Res = info0.GetShape().GetNumDimensions() == info1.GetShape().GetNumDimensions();
122 }
123};
124
Derek Lamberti5f400d62019-03-25 15:41:58 +0000125struct ShapesAreSameTotalSize : public Rule
126{
127 ShapesAreSameTotalSize(const TensorInfo& info0, const TensorInfo& info1)
128 {
129 m_Res = info0.GetNumElements() == info1.GetNumElements();
130 }
131};
132
Derek Lamberti50db4e82019-03-13 14:16:15 +0000133struct ShapesAreBroadcastCompatible : public Rule
134{
135 unsigned int CalcInputSize(const TensorShape& in, const TensorShape& out, unsigned int idx)
136 {
137 unsigned int offset = out.GetNumDimensions() - in.GetNumDimensions();
138 unsigned int sizeIn = (idx < offset) ? 1 : in[idx-offset];
139 return sizeIn;
140 }
141
142 ShapesAreBroadcastCompatible(const TensorInfo& in0, const TensorInfo& in1, const TensorInfo& out)
143 {
144 const TensorShape& shape0 = in0.GetShape();
145 const TensorShape& shape1 = in1.GetShape();
146 const TensorShape& outShape = out.GetShape();
147
148 for (unsigned int i=0; i < outShape.GetNumDimensions() && m_Res; i++)
149 {
150 unsigned int sizeOut = outShape[i];
151 unsigned int sizeIn0 = CalcInputSize(shape0, outShape, i);
152 unsigned int sizeIn1 = CalcInputSize(shape1, outShape, i);
153
154 m_Res &= ((sizeIn0 == sizeOut) || (sizeIn0 == 1)) &&
155 ((sizeIn1 == sizeOut) || (sizeIn1 == 1));
156 }
157 }
158};
159} // namespace
160
161
arovir011c7c81b2018-10-08 11:34:28 +0100162bool RefLayerSupport::IsActivationSupported(const TensorInfo& input,
163 const TensorInfo& output,
164 const ActivationDescriptor& descriptor,
165 Optional<std::string&> reasonIfUnsupported) const
166{
Derek Lamberti50db4e82019-03-13 14:16:15 +0000167 bool supported = true;
168
169 // Define supported types.
Teresa Charlin18515e22019-04-24 10:17:46 +0100170 std::array<DataType,3> supportedTypes = {
Derek Lamberti50db4e82019-03-13 14:16:15 +0000171 DataType::Float32,
Teresa Charlin18515e22019-04-24 10:17:46 +0100172 DataType::QuantisedAsymm8,
173 DataType::QuantisedSymm16
Derek Lamberti50db4e82019-03-13 14:16:15 +0000174 };
175
176 supported &= CheckSupportRule(TypeAnyOf(input, supportedTypes), reasonIfUnsupported,
177 "Reference activation: input type not supported.");
178
179 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
180 "Reference activation: output type not supported.");
181
182 supported &= CheckSupportRule(TypesAreEqual(input, output), reasonIfUnsupported,
183 "Reference activation: input and output types mismatched.");
184
185 supported &= CheckSupportRule(ShapesAreSameRank(input, output), reasonIfUnsupported,
186 "Reference activation: input and output shapes are of different rank.");
187
188
189 struct ActivationFunctionSupported : public Rule
190 {
191 ActivationFunctionSupported(const ActivationDescriptor& desc)
192 {
193 switch(desc.m_Function)
194 {
195 case ActivationFunction::Abs:
196 case ActivationFunction::BoundedReLu:
197 case ActivationFunction::LeakyReLu:
198 case ActivationFunction::Linear:
199 case ActivationFunction::ReLu:
200 case ActivationFunction::Sigmoid:
201 case ActivationFunction::SoftReLu:
202 case ActivationFunction::Sqrt:
203 case ActivationFunction::Square:
204 case ActivationFunction::TanH:
205 {
206 m_Res = true;
207 break;
208 }
209 default:
210 {
211 m_Res = false;
212 break;
213 }
214 }
215 }
216 };
217
218 // Function is supported
219 supported &= CheckSupportRule(ActivationFunctionSupported(descriptor), reasonIfUnsupported,
220 "Reference activation: function not supported.");
221
222 return supported;
arovir011c7c81b2018-10-08 11:34:28 +0100223}
224
225bool RefLayerSupport::IsAdditionSupported(const TensorInfo& input0,
226 const TensorInfo& input1,
227 const TensorInfo& output,
228 Optional<std::string&> reasonIfUnsupported) const
229{
Derek Lamberti50db4e82019-03-13 14:16:15 +0000230 bool supported = true;
231
Sadik Armagan2999a022019-04-09 14:20:12 +0100232 std::array<DataType,3> supportedTypes = {
Derek Lamberti50db4e82019-03-13 14:16:15 +0000233 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100234 DataType::QuantisedAsymm8,
235 DataType::QuantisedSymm16
Derek Lamberti50db4e82019-03-13 14:16:15 +0000236 };
237
238 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
239 "Reference addition: input 0 is not a supported type.");
240
241 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
242 "Reference addition: input 1 is not a supported type.");
243
244 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
245 "Reference addition: output is not a supported type.");
246
247 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
248 "Reference addition: input 0 and Input 1 types are mismatched");
249
250 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
251 "Reference addition: input and output types are mismatched");
252
253 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
254 "Reference addition: shapes are not suitable for implicit broadcast.");
255
256 return supported;
arovir011c7c81b2018-10-08 11:34:28 +0100257}
258
259bool RefLayerSupport::IsBatchNormalizationSupported(const TensorInfo& input,
260 const TensorInfo& output,
261 const TensorInfo& mean,
262 const TensorInfo& var,
263 const TensorInfo& beta,
264 const TensorInfo& gamma,
265 const BatchNormalizationDescriptor& descriptor,
266 Optional<std::string&> reasonIfUnsupported) const
267{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100268 ignore_unused(output);
269 ignore_unused(mean);
270 ignore_unused(var);
271 ignore_unused(beta);
272 ignore_unused(gamma);
273 ignore_unused(descriptor);
274 return IsSupportedForDataTypeRef(reasonIfUnsupported,
275 input.GetDataType(),
276 &TrueFunc<>,
277 &TrueFunc<>);
arovir011c7c81b2018-10-08 11:34:28 +0100278}
279
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +0000280bool RefLayerSupport::IsBatchToSpaceNdSupported(const TensorInfo& input,
281 const TensorInfo& output,
282 const BatchToSpaceNdDescriptor& descriptor,
283 Optional<std::string&> reasonIfUnsupported) const
284{
285 ignore_unused(descriptor);
286 return (IsSupportedForDataTypeRef(reasonIfUnsupported,
287 input.GetDataType(),
288 &TrueFunc<>,
289 &TrueFunc<>) &&
290 IsSupportedForDataTypeRef(reasonIfUnsupported,
291 output.GetDataType(),
292 &TrueFunc<>,
293 &TrueFunc<>));
294}
295
Jim Flynn906f9462019-05-10 13:55:21 +0100296bool RefLayerSupport::IsConcatSupported(const std::vector<const TensorInfo*> inputs,
297 const TensorInfo& output,
298 const OriginsDescriptor& descriptor,
299 Optional<std::string&> reasonIfUnsupported) const
300{
301 ARMNN_NO_DEPRECATE_WARN_BEGIN
302 return IsMergerSupported(inputs, output, descriptor, reasonIfUnsupported);
303 ARMNN_NO_DEPRECATE_WARN_END
304}
305
arovir011c7c81b2018-10-08 11:34:28 +0100306bool RefLayerSupport::IsConstantSupported(const TensorInfo& output,
307 Optional<std::string&> reasonIfUnsupported) const
308{
Nina Drozd58ef2c62019-05-16 12:09:18 +0100309 std::array<DataType,4> supportedTypes = {
310 DataType::Float32,
311 DataType::Signed32,
312 DataType::QuantisedAsymm8,
313 DataType::QuantisedSymm16
314 };
315
316 return CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
317 "Reference constant: output is not a supported type.");
arovir011c7c81b2018-10-08 11:34:28 +0100318}
319
320bool RefLayerSupport::IsConvertFp16ToFp32Supported(const TensorInfo& input,
321 const TensorInfo& output,
322 Optional<std::string&> reasonIfUnsupported) const
323{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100324 return (IsSupportedForDataTypeGeneric(reasonIfUnsupported,
325 input.GetDataType(),
326 &TrueFunc<>,
327 &FalseInputFuncF32<>,
narpra01db2b1602019-01-23 15:23:11 +0000328 &FalseFuncU8<>,
kevmay012b4d88e2019-01-24 14:05:09 +0000329 &FalseFuncI32<>,
330 &FalseFuncU8<>) &&
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100331 IsSupportedForDataTypeGeneric(reasonIfUnsupported,
332 output.GetDataType(),
333 &FalseOutputFuncF16<>,
334 &TrueFunc<>,
narpra01db2b1602019-01-23 15:23:11 +0000335 &FalseFuncU8<>,
kevmay012b4d88e2019-01-24 14:05:09 +0000336 &FalseFuncI32<>,
337 &FalseFuncU8<>));
arovir011c7c81b2018-10-08 11:34:28 +0100338}
339
340bool RefLayerSupport::IsConvertFp32ToFp16Supported(const TensorInfo& input,
341 const TensorInfo& output,
342 Optional<std::string&> reasonIfUnsupported) const
343{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100344 return (IsSupportedForDataTypeGeneric(reasonIfUnsupported,
345 input.GetDataType(),
346 &FalseInputFuncF16<>,
347 &TrueFunc<>,
narpra01db2b1602019-01-23 15:23:11 +0000348 &FalseFuncU8<>,
kevmay012b4d88e2019-01-24 14:05:09 +0000349 &FalseFuncI32<>,
350 &FalseFuncU8<>) &&
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100351 IsSupportedForDataTypeGeneric(reasonIfUnsupported,
352 output.GetDataType(),
353 &TrueFunc<>,
354 &FalseOutputFuncF32<>,
narpra01db2b1602019-01-23 15:23:11 +0000355 &FalseFuncU8<>,
kevmay012b4d88e2019-01-24 14:05:09 +0000356 &FalseFuncI32<>,
357 &FalseFuncU8<>));
arovir011c7c81b2018-10-08 11:34:28 +0100358}
359
360bool RefLayerSupport::IsConvolution2dSupported(const TensorInfo& input,
361 const TensorInfo& output,
362 const Convolution2dDescriptor& descriptor,
363 const TensorInfo& weights,
364 const Optional<TensorInfo>& biases,
365 Optional<std::string&> reasonIfUnsupported) const
366{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100367 ignore_unused(output);
368 ignore_unused(descriptor);
369 ignore_unused(weights);
370 ignore_unused(biases);
371 return IsSupportedForDataTypeRef(reasonIfUnsupported,
372 input.GetDataType(),
373 &TrueFunc<>,
374 &TrueFunc<>);
arovir011c7c81b2018-10-08 11:34:28 +0100375}
376
Nattapat Chaimanowongcfdcadf2018-12-06 11:54:33 +0000377bool RefLayerSupport::IsDebugSupported(const TensorInfo& input,
378 const TensorInfo& output,
Nattapat Chaimanowongcfdcadf2018-12-06 11:54:33 +0000379 Optional<std::string&> reasonIfUnsupported) const
380{
381 ignore_unused(output);
Nattapat Chaimanowongcfdcadf2018-12-06 11:54:33 +0000382 return IsSupportedForDataTypeRef(reasonIfUnsupported,
383 input.GetDataType(),
384 &TrueFunc<>,
385 &TrueFunc<>);
386}
387
arovir011c7c81b2018-10-08 11:34:28 +0100388bool RefLayerSupport::IsDepthwiseConvolutionSupported(const TensorInfo& input,
389 const TensorInfo& output,
390 const DepthwiseConvolution2dDescriptor& descriptor,
391 const TensorInfo& weights,
392 const Optional<TensorInfo>& biases,
393 Optional<std::string&> reasonIfUnsupported) const
394{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100395 ignore_unused(output);
396 ignore_unused(descriptor);
397 ignore_unused(weights);
398 ignore_unused(biases);
399 return IsSupportedForDataTypeRef(reasonIfUnsupported,
400 input.GetDataType(),
401 &TrueFunc<>,
402 &TrueFunc<>);
arovir011c7c81b2018-10-08 11:34:28 +0100403}
404
Nattapat Chaimanowong8a54ac02019-03-29 15:25:04 +0000405bool RefLayerSupport::IsDequantizeSupported(const TensorInfo& input,
406 const TensorInfo& output,
407 Optional<std::string&> reasonIfUnsupported) const
408{
Nattapat Chaimanowongafa4e3a2019-04-02 11:41:45 +0100409 bool supported = true;
410
411 std::array<DataType,2> supportedInputTypes = {
412 DataType::QuantisedAsymm8,
413 DataType::QuantisedSymm16
414 };
415
416 supported &= CheckSupportRule(TypeAnyOf(input, supportedInputTypes), reasonIfUnsupported,
417 "Reference dequantize: input type not supported.");
418
419 std::array<DataType,2> supportedOutputTypes = {
420 DataType::Float32,
421 };
422
423 supported &= CheckSupportRule(TypeAnyOf(output, supportedOutputTypes), reasonIfUnsupported,
424 "Reference dequantize: output type not supported.");
425
426 supported &= CheckSupportRule(ShapesAreSameTotalSize(input, output), reasonIfUnsupported,
427 "Reference dequantize: input and output shapes have different num total elements.");
428
429 return supported;
Nattapat Chaimanowong8a54ac02019-03-29 15:25:04 +0000430}
431
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +0000432bool RefLayerSupport::IsDetectionPostProcessSupported(const armnn::TensorInfo& input0,
433 const armnn::TensorInfo& input1,
434 const armnn::DetectionPostProcessDescriptor& descriptor,
435 armnn::Optional<std::string&> reasonIfUnsupported) const
436{
437 ignore_unused(input1);
438 return IsSupportedForDataTypeRef(reasonIfUnsupported,
439 input0.GetDataType(),
440 &TrueFunc<>,
441 &TrueFunc<>);
442}
443
Pablo Tellof0bd6832019-04-26 17:58:13 +0100444bool RefLayerSupport::IsDilatedDepthwiseConvolutionSupported(const TensorInfo& input,
445 const TensorInfo& output,
446 const DepthwiseConvolution2dDescriptor& descriptor,
447 const TensorInfo& weights,
448 const Optional<TensorInfo>& biases,
449 Optional<std::string&> reasonIfUnsupported) const
450{
451 if (descriptor.m_DilationY == 1 && descriptor.m_DilationY == 1)
452 {
453 return IsDepthwiseConvolutionSupported(input, output, descriptor, weights, biases, reasonIfUnsupported);
454 }
455 else
456 {
457 if (reasonIfUnsupported)
458 {
459 reasonIfUnsupported.value() = "Reference Depthwise Convolution: Dilation parameters must be 1";
460 }
461 return false;
462 }
463}
464
465
466 bool RefLayerSupport::IsDivisionSupported(const TensorInfo& input0,
arovir011c7c81b2018-10-08 11:34:28 +0100467 const TensorInfo& input1,
468 const TensorInfo& output,
469 Optional<std::string&> reasonIfUnsupported) const
470{
Sadik Armagan2999a022019-04-09 14:20:12 +0100471 bool supported = true;
472
473 std::array<DataType,3> supportedTypes = {
474 DataType::Float32,
475 DataType::QuantisedAsymm8,
476 DataType::QuantisedSymm16
477 };
478
479 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
480 "Reference division: input 0 is not a supported type.");
481
482 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
483 "Reference division: input 1 is not a supported type.");
484
485 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
486 "Reference division: output is not a supported type.");
487
488 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
489 "Reference division: input 0 and Input 1 types are mismatched");
490
491 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
492 "Reference division: input and output types are mismatched");
493
494 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
495 "Reference division: shapes are not suitable for implicit broadcast.");
496
497 return supported;
arovir011c7c81b2018-10-08 11:34:28 +0100498}
499
FrancisMurtagh30cdfca2018-12-18 12:57:35 +0000500bool RefLayerSupport::IsEqualSupported(const TensorInfo& input0,
501 const TensorInfo& input1,
502 const TensorInfo& output,
503 Optional<std::string&> reasonIfUnsupported) const
504{
505 ignore_unused(input0);
506 ignore_unused(input1);
507 ignore_unused(output);
508 ignore_unused(reasonIfUnsupported);
509 return IsSupportedForDataTypeRef(reasonIfUnsupported,
510 input0.GetDataType(),
511 &TrueFunc<>,
512 &TrueFunc<>);
513}
514
arovir011c7c81b2018-10-08 11:34:28 +0100515bool RefLayerSupport::IsFakeQuantizationSupported(const TensorInfo& input,
516 const FakeQuantizationDescriptor& descriptor,
517 Optional<std::string&> reasonIfUnsupported) const
518{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100519 ignore_unused(descriptor);
520 return IsSupportedForDataTypeRef(reasonIfUnsupported,
521 input.GetDataType(),
522 &TrueFunc<>,
523 &FalseFuncU8<>);
arovir011c7c81b2018-10-08 11:34:28 +0100524}
525
526bool RefLayerSupport::IsFloorSupported(const TensorInfo& input,
527 const TensorInfo& output,
528 Optional<std::string&> reasonIfUnsupported) const
529{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100530 ignore_unused(output);
531 return IsSupportedForDataTypeRef(reasonIfUnsupported,
532 input.GetDataType(),
533 &TrueFunc<>,
534 &FalseFuncU8<>);
arovir011c7c81b2018-10-08 11:34:28 +0100535}
536
537bool RefLayerSupport::IsFullyConnectedSupported(const TensorInfo& input,
538 const TensorInfo& output,
539 const TensorInfo& weights,
540 const TensorInfo& biases,
541 const FullyConnectedDescriptor& descriptor,
542 Optional<std::string&> reasonIfUnsupported) const
543{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100544 ignore_unused(output);
545 ignore_unused(weights);
546 ignore_unused(biases);
547 ignore_unused(descriptor);
548 return IsSupportedForDataTypeRef(reasonIfUnsupported,
549 input.GetDataType(),
550 &TrueFunc<>,
551 &TrueFunc<>);
arovir011c7c81b2018-10-08 11:34:28 +0100552}
553
narpra014951d842019-01-18 16:53:53 +0000554bool RefLayerSupport::IsGatherSupported(const armnn::TensorInfo& input0,
555 const armnn::TensorInfo& input1,
556 const armnn::TensorInfo& output,
557 armnn::Optional<std::string&> reasonIfUnsupported) const
558{
559 ignore_unused(input1);
560 ignore_unused(output);
561 return IsSupportedForDataTypeRef(reasonIfUnsupported,
562 input0.GetDataType(),
563 &TrueFunc<>,
564 &TrueFunc<>);
565}
566
FrancisMurtagh878f0232018-12-19 10:56:15 +0000567bool RefLayerSupport::IsGreaterSupported(const TensorInfo& input0,
568 const TensorInfo& input1,
569 const TensorInfo& output,
570 Optional<std::string&> reasonIfUnsupported) const
571{
572 ignore_unused(input0);
573 ignore_unused(input1);
574 ignore_unused(output);
575 ignore_unused(reasonIfUnsupported);
576 return IsSupportedForDataTypeRef(reasonIfUnsupported,
577 input0.GetDataType(),
578 &TrueFunc<>,
579 &TrueFunc<>);
580}
581
arovir011c7c81b2018-10-08 11:34:28 +0100582bool RefLayerSupport::IsInputSupported(const TensorInfo& input,
583 Optional<std::string&> reasonIfUnsupported) const
584{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100585 return IsSupportedForDataTypeRef(reasonIfUnsupported,
586 input.GetDataType(),
587 &TrueFunc<>,
588 &TrueFunc<>);
arovir011c7c81b2018-10-08 11:34:28 +0100589}
590
591bool RefLayerSupport::IsL2NormalizationSupported(const TensorInfo& input,
592 const TensorInfo& output,
593 const L2NormalizationDescriptor& descriptor,
594 Optional<std::string&> reasonIfUnsupported) const
595{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100596 ignore_unused(output);
597 ignore_unused(descriptor);
598 return IsSupportedForDataTypeRef(reasonIfUnsupported,
599 input.GetDataType(),
600 &TrueFunc<>,
601 &FalseFuncU8<>);
arovir011c7c81b2018-10-08 11:34:28 +0100602}
603
604bool RefLayerSupport::IsLstmSupported(const TensorInfo& input,
605 const TensorInfo& outputStateIn,
606 const TensorInfo& cellStateIn,
607 const TensorInfo& scratchBuffer,
608 const TensorInfo& outputStateOut,
609 const TensorInfo& cellStateOut,
610 const TensorInfo& output,
611 const LstmDescriptor& descriptor,
612 const TensorInfo& inputToForgetWeights,
613 const TensorInfo& inputToCellWeights,
614 const TensorInfo& inputToOutputWeights,
615 const TensorInfo& recurrentToForgetWeights,
616 const TensorInfo& recurrentToCellWeights,
617 const TensorInfo& recurrentToOutputWeights,
618 const TensorInfo& forgetGateBias,
619 const TensorInfo& cellBias,
620 const TensorInfo& outputGateBias,
621 const TensorInfo* inputToInputWeights,
622 const TensorInfo* recurrentToInputWeights,
623 const TensorInfo* cellToInputWeights,
624 const TensorInfo* inputGateBias,
625 const TensorInfo* projectionWeights,
626 const TensorInfo* projectionBias,
627 const TensorInfo* cellToForgetWeights,
628 const TensorInfo* cellToOutputWeights,
629 Optional<std::string&> reasonIfUnsupported) const
630{
telsoa01c577f2c2018-08-31 09:22:23 +0100631 ignore_unused(descriptor);
632 ignore_unused(inputToForgetWeights);
633 ignore_unused(inputToCellWeights);
634 ignore_unused(inputToOutputWeights);
635 ignore_unused(recurrentToForgetWeights);
636 ignore_unused(recurrentToCellWeights);
637 ignore_unused(recurrentToOutputWeights);
638 ignore_unused(forgetGateBias);
639 ignore_unused(cellBias);
640 ignore_unused(outputGateBias);
641 ignore_unused(inputToInputWeights);
642 ignore_unused(recurrentToInputWeights);
643 ignore_unused(cellToInputWeights);
644 ignore_unused(inputGateBias);
645 ignore_unused(projectionWeights);
646 ignore_unused(projectionBias);
647 ignore_unused(cellToForgetWeights);
648 ignore_unused(cellToOutputWeights);
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +0100649
650 bool supported = true;
651
652 std::array<DataType,2> supportedTypes = {
Conor Kennedyb9971c92019-05-07 07:14:23 +0100653 DataType::Float32,
654 DataType::QuantisedSymm16
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +0100655 };
656
657 supported &= CheckSupportRule(TypeAnyOf(input, supportedTypes), reasonIfUnsupported,
658 "Reference Lstm: input is not a supported type.");
659
660 supported &= CheckSupportRule(TypesAreEqual(input, outputStateIn), reasonIfUnsupported,
661 "Reference Lstm: input and outputStateIn types are mismatched");
662
663 supported &= CheckSupportRule(TypesAreEqual(input, cellStateIn), reasonIfUnsupported,
664 "Reference Lstm: input and cellStateIn types are mismatched");
665
666 supported &= CheckSupportRule(TypesAreEqual(input, scratchBuffer), reasonIfUnsupported,
667 "Reference Lstm: input and scratchBuffer types are mismatched");
668
669 supported &= CheckSupportRule(TypesAreEqual(input, outputStateOut), reasonIfUnsupported,
670 "Reference Lstm: input and outputStateOut types are mismatched");
671
672 supported &= CheckSupportRule(TypesAreEqual(input, cellStateOut), reasonIfUnsupported,
673 "Reference Lstm: input and cellStateOut types are mismatched");
674
675 supported &= CheckSupportRule(TypesAreEqual(input, output), reasonIfUnsupported,
676 "Reference Lstm: input and output types are mismatched");
677
678 return supported;
telsoa01c577f2c2018-08-31 09:22:23 +0100679}
680
saoste012df12b32018-11-28 16:57:20 +0000681bool RefLayerSupport::IsMaximumSupported(const TensorInfo& input0,
682 const TensorInfo& input1,
683 const TensorInfo& output,
684 Optional<std::string&> reasonIfUnsupported) const
685{
Sadik Armagan2999a022019-04-09 14:20:12 +0100686 bool supported = true;
687
688 std::array<DataType,3> supportedTypes = {
689 DataType::Float32,
690 DataType::QuantisedAsymm8,
691 DataType::QuantisedSymm16
692 };
693
694 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
695 "Reference maximum: input 0 is not a supported type.");
696
697 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
698 "Reference maximum: input 1 is not a supported type.");
699
700 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
701 "Reference maximum: output is not a supported type.");
702
703 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
704 "Reference maximum: input 0 and Input 1 types are mismatched");
705
706 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
707 "Reference maximum: input and output types are mismatched");
708
709 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
710 "Reference maximum: shapes are not suitable for implicit broadcast.");
711
712 return supported;
saoste012df12b32018-11-28 16:57:20 +0000713}
714
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100715bool RefLayerSupport::IsMeanSupported(const TensorInfo& input,
716 const TensorInfo& output,
717 const MeanDescriptor& descriptor,
718 Optional<std::string&> reasonIfUnsupported) const
narpra0132b90462018-09-13 11:07:48 +0100719{
narpra011e4c31d2018-09-28 11:07:51 +0100720 ignore_unused(output);
721 ignore_unused(descriptor);
722 return IsSupportedForDataTypeRef(reasonIfUnsupported,
723 input.GetDataType(),
724 &TrueFunc<>,
725 &TrueFunc<>);
narpra0132b90462018-09-13 11:07:48 +0100726}
727
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100728bool RefLayerSupport::IsMergerSupported(const std::vector<const TensorInfo*> inputs,
Nikhil Raj8599a412018-11-19 14:51:07 +0000729 const TensorInfo& output,
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100730 const OriginsDescriptor& descriptor,
731 Optional<std::string&> reasonIfUnsupported) const
732{
733 ignore_unused(descriptor);
Jim Flynncbb66aa2019-05-15 13:03:54 +0100734
735 bool supported = true;
736 std::array<DataType,3> supportedTypes =
737 {
738 DataType::Float32,
739 DataType::QuantisedAsymm8,
740 DataType::QuantisedSymm16
741 };
742
743 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
744 "Reference concatenation: output type not supported");
745 for (const TensorInfo* input : inputs)
746 {
747 supported &= CheckSupportRule(TypeAnyOf(*input, supportedTypes), reasonIfUnsupported,
748 "Reference concatenation: input type not supported");
749
750 supported &= CheckSupportRule(TypesAreEqual(*input, output), reasonIfUnsupported,
751 "Reference concatenation: input and output types mismatched.");
752 }
753
754 return supported;
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100755}
756
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000757bool RefLayerSupport::IsMemCopySupported(const TensorInfo &input,
758 const TensorInfo &output,
759 Optional<std::string &> reasonIfUnsupported) const
760{
761 ignore_unused(output);
kevmay012b4d88e2019-01-24 14:05:09 +0000762 return IsSupportedForDataTypeGeneric(reasonIfUnsupported,
763 input.GetDataType(),
764 &TrueFunc<>,
765 &TrueFunc<>,
766 &TrueFunc<>,
767 &FalseFuncI32<>,
768 &TrueFunc<>);
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000769}
770
Éanna Ó Catháin20e58802018-12-04 10:29:06 +0000771bool RefLayerSupport::IsMinimumSupported(const TensorInfo& input0,
772 const TensorInfo& input1,
773 const TensorInfo& output,
774 Optional<std::string&> reasonIfUnsupported) const
775{
Sadik Armagan2999a022019-04-09 14:20:12 +0100776 bool supported = true;
777
778 std::array<DataType,3> supportedTypes = {
779 DataType::Float32,
780 DataType::QuantisedAsymm8,
781 DataType::QuantisedSymm16
782 };
783
784 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
785 "Reference minimum: input 0 is not a supported type.");
786
787 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
788 "Reference minimum: input 1 is not a supported type.");
789
790 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
791 "Reference minimum: output is not a supported type.");
792
793 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
794 "Reference minimum: input 0 and Input 1 types are mismatched");
795
796 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
797 "Reference minimum: input and output types are mismatched");
798
799 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
800 "Reference minimum: shapes are not suitable for implicit broadcast.");
801
802 return supported;
Éanna Ó Catháin20e58802018-12-04 10:29:06 +0000803}
804
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100805bool RefLayerSupport::IsMultiplicationSupported(const TensorInfo& input0,
806 const TensorInfo& input1,
807 const TensorInfo& output,
808 Optional<std::string&> reasonIfUnsupported) const
809{
Sadik Armagan2999a022019-04-09 14:20:12 +0100810 bool supported = true;
811
812 std::array<DataType,3> supportedTypes = {
813 DataType::Float32,
814 DataType::QuantisedAsymm8,
815 DataType::QuantisedSymm16
816 };
817
818 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
819 "Reference multiplication: input 0 is not a supported type.");
820
821 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
822 "Reference multiplication: input 1 is not a supported type.");
823
824 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
825 "Reference multiplication: output is not a supported type.");
826
827 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
828 "Reference multiplication: input 0 and Input 1 types are mismatched");
829
830 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
831 "Reference multiplication: input and output types are mismatched");
832
833 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
834 "Reference multiplication: shapes are not suitable for implicit broadcast.");
835
836 return supported;
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100837}
838
839bool RefLayerSupport::IsNormalizationSupported(const TensorInfo& input,
840 const TensorInfo& output,
841 const NormalizationDescriptor& descriptor,
842 Optional<std::string&> reasonIfUnsupported) const
Nina Drozd661dfa72018-10-02 11:14:17 +0100843{
844 ignore_unused(output);
845 ignore_unused(descriptor);
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100846 return IsSupportedForDataTypeRef(reasonIfUnsupported,
847 input.GetDataType(),
848 &TrueFunc<>,
849 &FalseFuncU8<>);
850}
851
852bool RefLayerSupport::IsOutputSupported(const TensorInfo& output,
853 Optional<std::string&> reasonIfUnsupported) const
854{
kevmay012b4d88e2019-01-24 14:05:09 +0000855 return IsSupportedForDataTypeGeneric(reasonIfUnsupported,
856 output.GetDataType(),
857 &TrueFunc<>,
858 &TrueFunc<>,
859 &TrueFunc<>,
860 &FalseFuncI32<>,
861 &TrueFunc<>);
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100862}
863
864bool RefLayerSupport::IsPadSupported(const TensorInfo& input,
865 const TensorInfo& output,
866 const PadDescriptor& descriptor,
867 Optional<std::string&> reasonIfUnsupported) const
868{
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100869 ignore_unused(output);
870 ignore_unused(descriptor);
jimfly01f6ba7472018-12-04 10:09:52 +0000871 return IsSupportedForDataTypeRef(reasonIfUnsupported,
872 input.GetDataType(),
873 &TrueFunc<>,
874 &TrueFunc<>);
Nina Drozd661dfa72018-10-02 11:14:17 +0100875}
876
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100877bool RefLayerSupport::IsPermuteSupported(const TensorInfo& input,
878 const TensorInfo& output,
879 const PermuteDescriptor& descriptor,
880 Optional<std::string&> reasonIfUnsupported) const
881{
882 ignore_unused(output);
883 ignore_unused(descriptor);
884 return IsSupportedForDataTypeRef(reasonIfUnsupported,
885 input.GetDataType(),
886 &TrueFunc<>,
887 &TrueFunc<>);
888}
889
890bool RefLayerSupport::IsPooling2dSupported(const TensorInfo& input,
891 const TensorInfo& output,
892 const Pooling2dDescriptor& descriptor,
893 Optional<std::string&> reasonIfUnsupported) const
894{
895 ignore_unused(output);
896 ignore_unused(descriptor);
897 return IsSupportedForDataTypeRef(reasonIfUnsupported,
898 input.GetDataType(),
899 &TrueFunc<>,
900 &TrueFunc<>);
901}
902
Derek Lamberti5f400d62019-03-25 15:41:58 +0000903bool RefLayerSupport::IsQuantizeSupported(const TensorInfo& input,
904 const TensorInfo& output,
905 Optional<std::string&> reasonIfUnsupported) const
906{
907 bool supported = true;
908
909 // Define supported output types.
910 std::array<DataType,2> supportedInputTypes = {
911 DataType::Float32,
912 };
913
914 supported &= CheckSupportRule(TypeAnyOf(input, supportedInputTypes), reasonIfUnsupported,
915 "Reference quantize: input type not supported.");
916
917 // Define supported output types.
918 std::array<DataType,2> supportedOutputTypes = {
919 DataType::QuantisedAsymm8,
920 DataType::QuantisedSymm16
921 };
922 supported &= CheckSupportRule(TypeAnyOf(output, supportedOutputTypes), reasonIfUnsupported,
923 "Reference quantize: output type not supported.");
924
925 supported &= CheckSupportRule(ShapesAreSameTotalSize(input, output), reasonIfUnsupported,
926 "Reference quantize: input and output shapes have different num total elements.");
927
928 return supported;
929}
930
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100931bool RefLayerSupport::IsReshapeSupported(const TensorInfo& input,
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000932 const ReshapeDescriptor& descriptor,
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100933 Optional<std::string&> reasonIfUnsupported) const
934{
Matteo Martincigh992d6dc2019-01-10 17:34:20 +0000935 ignore_unused(descriptor);
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100936 return IsSupportedForDataTypeRef(reasonIfUnsupported,
937 input.GetDataType(),
938 &TrueFunc<>,
939 &TrueFunc<>);
940}
941
942bool RefLayerSupport::IsResizeBilinearSupported(const TensorInfo& input,
Sadik Armaganc625f002018-12-17 11:32:16 +0000943 const TensorInfo& output,
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100944 Optional<std::string&> reasonIfUnsupported) const
945{
Sadik Armaganc625f002018-12-17 11:32:16 +0000946 ignore_unused(output);
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100947 return IsSupportedForDataTypeRef(reasonIfUnsupported,
948 input.GetDataType(),
949 &TrueFunc<>,
950 &TrueFunc<>);
951}
952
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +0000953bool RefLayerSupport::IsRsqrtSupported(const TensorInfo& input,
954 const TensorInfo& output,
955 Optional<std::string&> reasonIfUnsupported) const
956{
957 ignore_unused(output);
958 return IsSupportedForDataTypeRef(reasonIfUnsupported,
959 input.GetDataType(),
960 &TrueFunc<>,
961 &FalseFuncU8<>);
962}
963
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100964bool RefLayerSupport::IsSoftmaxSupported(const TensorInfo& input,
965 const TensorInfo& output,
966 const SoftmaxDescriptor& descriptor,
967 Optional<std::string&> reasonIfUnsupported) const
968{
969 ignore_unused(output);
970 ignore_unused(descriptor);
971 return IsSupportedForDataTypeRef(reasonIfUnsupported,
972 input.GetDataType(),
973 &TrueFunc<>,
974 &TrueFunc<>);
975}
976
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000977bool RefLayerSupport::IsSpaceToBatchNdSupported(const TensorInfo& input,
978 const TensorInfo& output,
979 const SpaceToBatchNdDescriptor& descriptor,
980 Optional<std::string&> reasonIfUnsupported) const
981{
982 ignore_unused(output);
983 ignore_unused(descriptor);
984 return IsSupportedForDataTypeRef(reasonIfUnsupported,
985 input.GetDataType(),
986 &TrueFunc<>,
987 &TrueFunc<>);
988}
989
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +0100990bool RefLayerSupport::IsSplitterSupported(const TensorInfo& input,
991 const ViewsDescriptor& descriptor,
992 Optional<std::string&> reasonIfUnsupported) const
993{
994 ignore_unused(descriptor);
995 return IsSupportedForDataTypeRef(reasonIfUnsupported,
996 input.GetDataType(),
997 &TrueFunc<>,
998 &TrueFunc<>);
999}
1000
Narumol Prangnawarat15eb5832019-05-20 15:31:05 +01001001bool RefLayerSupport::IsSplitterSupported(const TensorInfo& input,
1002 const std::vector<std::reference_wrapper<TensorInfo>>& outputs,
1003 const ViewsDescriptor& descriptor,
1004 Optional<std::string&> reasonIfUnsupported) const
1005{
1006 ignore_unused(descriptor);
1007 ignore_unused(outputs);
1008 return IsSupportedForDataTypeRef(reasonIfUnsupported,
1009 input.GetDataType(),
1010 &TrueFunc<>,
1011 &TrueFunc<>);
1012}
1013
Nattapat Chaimanowong1216b582018-11-23 15:33:41 +00001014bool RefLayerSupport::IsStridedSliceSupported(const TensorInfo& input,
1015 const TensorInfo& output,
1016 const StridedSliceDescriptor& descriptor,
1017 Optional<std::string&> reasonIfUnsupported) const
1018{
1019 ignore_unused(output);
1020 ignore_unused(descriptor);
1021 return IsSupportedForDataTypeRef(reasonIfUnsupported,
1022 input.GetDataType(),
1023 &TrueFunc<>,
1024 &TrueFunc<>);
1025}
1026
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +01001027bool RefLayerSupport::IsSubtractionSupported(const TensorInfo& input0,
1028 const TensorInfo& input1,
1029 const TensorInfo& output,
1030 Optional<std::string&> reasonIfUnsupported) const
1031{
Sadik Armagan2999a022019-04-09 14:20:12 +01001032 bool supported = true;
1033
1034 std::array<DataType,3> supportedTypes = {
1035 DataType::Float32,
1036 DataType::QuantisedAsymm8,
1037 DataType::QuantisedSymm16
1038 };
1039
1040 supported &= CheckSupportRule(TypeAnyOf(input0, supportedTypes), reasonIfUnsupported,
1041 "Reference subtraction: input 0 is not a supported type.");
1042
1043 supported &= CheckSupportRule(TypeAnyOf(input1, supportedTypes), reasonIfUnsupported,
1044 "Reference subtraction: input 1 is not a supported type.");
1045
1046 supported &= CheckSupportRule(TypeAnyOf(output, supportedTypes), reasonIfUnsupported,
1047 "Reference subtraction: output is not a supported type.");
1048
1049 supported &= CheckSupportRule(TypesAreEqual(input0, input1), reasonIfUnsupported,
1050 "Reference subtraction: input 0 and Input 1 types are mismatched");
1051
1052 supported &= CheckSupportRule(TypesAreEqual(input0, output), reasonIfUnsupported,
1053 "Reference subtraction: input and output types are mismatched");
1054
1055 supported &= CheckSupportRule(ShapesAreBroadcastCompatible(input0, input1, output), reasonIfUnsupported,
1056 "Reference subtraction: shapes are not suitable for implicit broadcast.");
1057
1058 return supported;
Aron Virginas-Tarb5acbb72018-10-15 11:11:51 +01001059}
1060
arovir011c7c81b2018-10-08 11:34:28 +01001061} // namespace armnn