1 /*
2 * Copyright (c) 2018-2020 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24 #include "arm_compute/core/Validate.h"
25 #include "arm_compute/runtime/NEON/functions/NEElementwiseOperations.h"
26 #include <src/core/NEON/kernels/NEElementwiseOperationKernel.h>
27
28 #include "arm_compute/core/ITensor.h"
29 #include "support/MemorySupport.h"
30
31 #include <utility>
32
33 namespace arm_compute
34 {
35 namespace experimental
36 {
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)37 void NEElementwiseMax::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
38 {
39 auto k = arm_compute::support::cpp14::make_unique<NEArithmeticOperationKernel>();
40 k->configure(ArithmeticOperation::MAX, input1, input2, output);
41 _kernel = std::move(k);
42 }
43
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)44 Status NEElementwiseMax::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
45 {
46 return NEArithmeticOperationKernel::validate(ArithmeticOperation::MAX, input1, input2, output);
47 }
48
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)49 void NEElementwiseMin::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
50 {
51 auto k = arm_compute::support::cpp14::make_unique<NEArithmeticOperationKernel>();
52 k->configure(ArithmeticOperation::MIN, input1, input2, output);
53 _kernel = std::move(k);
54 }
55
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)56 Status NEElementwiseMin::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
57 {
58 return NEArithmeticOperationKernel::validate(ArithmeticOperation::MIN, input1, input2, output);
59 }
60
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)61 void NEElementwiseSquaredDiff::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
62 {
63 auto k = arm_compute::support::cpp14::make_unique<NEArithmeticOperationKernel>();
64 k->configure(ArithmeticOperation::SQUARED_DIFF, input1, input2, output);
65 _kernel = std::move(k);
66 }
67
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)68 Status NEElementwiseSquaredDiff::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
69 {
70 return NEArithmeticOperationKernel::validate(ArithmeticOperation::SQUARED_DIFF, input1, input2, output);
71 }
72
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)73 void NEElementwiseDivision::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
74 {
75 auto k = arm_compute::support::cpp14::make_unique<NEDivisionOperationKernel>();
76 k->configure(input1, input2, output);
77 _kernel = std::move(k);
78 }
79
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)80 Status NEElementwiseDivision::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
81 {
82 return NEDivisionOperationKernel::validate(input1, input2, output);
83 }
84
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)85 void NEElementwisePower::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
86 {
87 auto k = arm_compute::support::cpp14::make_unique<NEPowerOperationKernel>();
88 k->configure(input1, input2, output);
89 _kernel = std::move(k);
90 }
91
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)92 Status NEElementwisePower::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
93 {
94 return NEPowerOperationKernel::validate(input1, input2, output);
95 }
96
97 template <ComparisonOperation COP>
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output)98 void NEElementwiseComparisonStatic<COP>::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output)
99 {
100 auto k = arm_compute::support::cpp14::make_unique<NEComparisonOperationKernel>();
101 k->configure(COP, input1, input2, output);
102 _kernel = std::move(k);
103 }
104
105 template <ComparisonOperation COP>
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)106 Status NEElementwiseComparisonStatic<COP>::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
107 {
108 return NEComparisonOperationKernel::validate(COP, input1, input2, output);
109 }
110
configure(const ITensorInfo * input1,const ITensorInfo * input2,ITensorInfo * output,ComparisonOperation op)111 void NEElementwiseComparison::configure(const ITensorInfo *input1, const ITensorInfo *input2, ITensorInfo *output, ComparisonOperation op)
112 {
113 auto k = arm_compute::support::cpp14::make_unique<NEComparisonOperationKernel>();
114 k->configure(op, input1, input2, output);
115 _kernel = std::move(k);
116 }
117
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,ComparisonOperation op)118 Status NEElementwiseComparison::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, ComparisonOperation op)
119 {
120 return NEComparisonOperationKernel::validate(op, input1, input2, output);
121 }
122
123 // Supported Specializations
124 template class NEElementwiseComparisonStatic<ComparisonOperation::Equal>;
125 template class NEElementwiseComparisonStatic<ComparisonOperation::NotEqual>;
126 template class NEElementwiseComparisonStatic<ComparisonOperation::Greater>;
127 template class NEElementwiseComparisonStatic<ComparisonOperation::GreaterEqual>;
128 template class NEElementwiseComparisonStatic<ComparisonOperation::Less>;
129 template class NEElementwiseComparisonStatic<ComparisonOperation::LessEqual>;
130 } // namespace experimental
131
132 struct NEElementwiseMax::Impl
133 {
134 const ITensor *src_0{ nullptr };
135 const ITensor *src_1{ nullptr };
136 ITensor *dst{ nullptr };
137 std::unique_ptr<experimental::NEElementwiseMax> op{ nullptr };
138 };
139
NEElementwiseMax()140 NEElementwiseMax::NEElementwiseMax()
141 : _impl(support::cpp14::make_unique<Impl>())
142 {
143 }
144 NEElementwiseMax::NEElementwiseMax(NEElementwiseMax &&) = default;
145 NEElementwiseMax &NEElementwiseMax::operator=(NEElementwiseMax &&) = default;
146 NEElementwiseMax::~NEElementwiseMax() = default;
147
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)148 void NEElementwiseMax::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
149 {
150 ARM_COMPUTE_UNUSED(act_info);
151 _impl->src_0 = input1;
152 _impl->src_1 = input2;
153 _impl->dst = output;
154 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseMax>();
155 _impl->op->configure(input1->info(), input2->info(), output->info());
156 }
157
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)158 Status NEElementwiseMax::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
159 {
160 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
161 return experimental::NEElementwiseMax::validate(input1, input2, output);
162 }
163
run()164 void NEElementwiseMax::run()
165 {
166 ITensorPack pack;
167 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
168 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
169 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
170 _impl->op->run(pack);
171 }
172
173 struct NEElementwiseMin::Impl
174 {
175 const ITensor *src_0{ nullptr };
176 const ITensor *src_1{ nullptr };
177 ITensor *dst{ nullptr };
178 std::unique_ptr<experimental::NEElementwiseMin> op{ nullptr };
179 };
180
NEElementwiseMin()181 NEElementwiseMin::NEElementwiseMin()
182 : _impl(support::cpp14::make_unique<Impl>())
183 {
184 }
185 NEElementwiseMin::NEElementwiseMin(NEElementwiseMin &&) = default;
186 NEElementwiseMin &NEElementwiseMin::operator=(NEElementwiseMin &&) = default;
187 NEElementwiseMin::~NEElementwiseMin() = default;
188
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)189 void NEElementwiseMin::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
190 {
191 ARM_COMPUTE_UNUSED(act_info);
192 _impl->src_0 = input1;
193 _impl->src_1 = input2;
194 _impl->dst = output;
195 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseMin>();
196 _impl->op->configure(input1->info(), input2->info(), output->info());
197 }
198
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)199 Status NEElementwiseMin::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
200 {
201 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
202 return experimental::NEElementwiseMin::validate(input1, input2, output);
203 }
204
run()205 void NEElementwiseMin::run()
206 {
207 ITensorPack pack;
208 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
209 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
210 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
211 _impl->op->run(pack);
212 }
213
214 struct NEElementwiseSquaredDiff::Impl
215 {
216 const ITensor *src_0{ nullptr };
217 const ITensor *src_1{ nullptr };
218 ITensor *dst{ nullptr };
219 std::unique_ptr<experimental::NEElementwiseSquaredDiff> op{ nullptr };
220 };
221
NEElementwiseSquaredDiff()222 NEElementwiseSquaredDiff::NEElementwiseSquaredDiff()
223 : _impl(support::cpp14::make_unique<Impl>())
224 {
225 }
226 NEElementwiseSquaredDiff::NEElementwiseSquaredDiff(NEElementwiseSquaredDiff &&) = default;
227 NEElementwiseSquaredDiff &NEElementwiseSquaredDiff::operator=(NEElementwiseSquaredDiff &&) = default;
228 NEElementwiseSquaredDiff::~NEElementwiseSquaredDiff() = default;
229
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)230 void NEElementwiseSquaredDiff::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
231 {
232 ARM_COMPUTE_UNUSED(act_info);
233 _impl->src_0 = input1;
234 _impl->src_1 = input2;
235 _impl->dst = output;
236 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseSquaredDiff>();
237 _impl->op->configure(input1->info(), input2->info(), output->info());
238 }
239
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)240 Status NEElementwiseSquaredDiff::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
241 {
242 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
243 return experimental::NEElementwiseSquaredDiff::validate(input1, input2, output);
244 }
245
run()246 void NEElementwiseSquaredDiff::run()
247 {
248 ITensorPack pack;
249 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
250 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
251 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
252 _impl->op->run(pack);
253 }
254
255 struct NEElementwiseDivision::Impl
256 {
257 const ITensor *src_0{ nullptr };
258 const ITensor *src_1{ nullptr };
259 ITensor *dst{ nullptr };
260 std::unique_ptr<experimental::NEElementwiseDivision> op{ nullptr };
261 };
262
NEElementwiseDivision()263 NEElementwiseDivision::NEElementwiseDivision()
264 : _impl(support::cpp14::make_unique<Impl>())
265 {
266 }
267 NEElementwiseDivision::NEElementwiseDivision(NEElementwiseDivision &&) = default;
268 NEElementwiseDivision &NEElementwiseDivision::operator=(NEElementwiseDivision &&) = default;
269 NEElementwiseDivision::~NEElementwiseDivision() = default;
270
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)271 void NEElementwiseDivision::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
272 {
273 ARM_COMPUTE_UNUSED(act_info);
274 _impl->src_0 = input1;
275 _impl->src_1 = input2;
276 _impl->dst = output;
277 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseDivision>();
278 _impl->op->configure(input1->info(), input2->info(), output->info());
279 }
280
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)281 Status NEElementwiseDivision::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
282 {
283 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
284 return experimental::NEElementwiseDivision::validate(input1, input2, output);
285 }
286
run()287 void NEElementwiseDivision::run()
288 {
289 ITensorPack pack;
290 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
291 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
292 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
293 _impl->op->run(pack);
294 }
295
296 struct NEElementwisePower::Impl
297 {
298 const ITensor *src_0{ nullptr };
299 const ITensor *src_1{ nullptr };
300 ITensor *dst{ nullptr };
301 std::unique_ptr<experimental::NEElementwisePower> op{ nullptr };
302 };
303
NEElementwisePower()304 NEElementwisePower::NEElementwisePower()
305 : _impl(support::cpp14::make_unique<Impl>())
306 {
307 }
308 NEElementwisePower::NEElementwisePower(NEElementwisePower &&) = default;
309 NEElementwisePower &NEElementwisePower::operator=(NEElementwisePower &&) = default;
310 NEElementwisePower::~NEElementwisePower() = default;
311
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)312 void NEElementwisePower::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
313 {
314 ARM_COMPUTE_UNUSED(act_info);
315 _impl->src_0 = input1;
316 _impl->src_1 = input2;
317 _impl->dst = output;
318 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwisePower>();
319 _impl->op->configure(input1->info(), input2->info(), output->info());
320 }
321
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)322 Status NEElementwisePower::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
323 {
324 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
325 return experimental::NEElementwisePower::validate(input1, input2, output);
326 }
327
run()328 void NEElementwisePower::run()
329 {
330 ITensorPack pack;
331 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
332 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
333 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
334 _impl->op->run(pack);
335 }
336
337 template <ComparisonOperation COP>
338 struct NEElementwiseComparisonStatic<COP>::Impl
339 {
340 const ITensor *src_0{ nullptr };
341 const ITensor *src_1{ nullptr };
342 ITensor *dst{ nullptr };
343 std::unique_ptr<experimental::NEElementwiseComparisonStatic<COP>> op{ nullptr };
344 };
345
346 template <ComparisonOperation COP>
NEElementwiseComparisonStatic()347 NEElementwiseComparisonStatic<COP>::NEElementwiseComparisonStatic()
348 : _impl(support::cpp14::make_unique<Impl>())
349 {
350 }
351 template <ComparisonOperation COP>
352 NEElementwiseComparisonStatic<COP>::NEElementwiseComparisonStatic(NEElementwiseComparisonStatic &&) = default;
353 template <ComparisonOperation COP>
354 NEElementwiseComparisonStatic<COP> &NEElementwiseComparisonStatic<COP>::operator=(NEElementwiseComparisonStatic &&) = default;
355 template <ComparisonOperation COP>
356 NEElementwiseComparisonStatic<COP>::~NEElementwiseComparisonStatic() = default;
357
358 template <ComparisonOperation COP>
configure(ITensor * input1,ITensor * input2,ITensor * output)359 void NEElementwiseComparisonStatic<COP>::configure(ITensor *input1, ITensor *input2, ITensor *output)
360 {
361 _impl->src_0 = input1;
362 _impl->src_1 = input2;
363 _impl->dst = output;
364 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseComparisonStatic<COP>>();
365 _impl->op->configure(input1->info(), input2->info(), output->info());
366 }
367
368 template <ComparisonOperation COP>
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)369 Status NEElementwiseComparisonStatic<COP>::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
370 {
371 return experimental::NEElementwiseComparisonStatic<COP>::validate(input1, input2, output);
372 }
373
374 template <ComparisonOperation COP>
run()375 void NEElementwiseComparisonStatic<COP>::run()
376 {
377 ITensorPack pack;
378 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
379 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
380 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
381 _impl->op->run(pack);
382 }
383
384 struct NEElementwiseComparison::Impl
385 {
386 const ITensor *src_0{ nullptr };
387 const ITensor *src_1{ nullptr };
388 ITensor *dst{ nullptr };
389 std::unique_ptr<experimental::NEElementwiseComparison> op{ nullptr };
390 };
391
NEElementwiseComparison()392 NEElementwiseComparison::NEElementwiseComparison()
393 : _impl(support::cpp14::make_unique<Impl>())
394 {
395 }
396 NEElementwiseComparison::NEElementwiseComparison(NEElementwiseComparison &&) = default;
397 NEElementwiseComparison &NEElementwiseComparison::operator=(NEElementwiseComparison &&) = default;
398 NEElementwiseComparison::~NEElementwiseComparison() = default;
399
configure(ITensor * input1,ITensor * input2,ITensor * output,ComparisonOperation op)400 void NEElementwiseComparison::configure(ITensor *input1, ITensor *input2, ITensor *output, ComparisonOperation op)
401 {
402 _impl->src_0 = input1;
403 _impl->src_1 = input2;
404 _impl->dst = output;
405 _impl->op = arm_compute::support::cpp14::make_unique<experimental::NEElementwiseComparison>();
406 _impl->op->configure(input1->info(), input2->info(), output->info(), op);
407 }
408
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,ComparisonOperation op)409 Status NEElementwiseComparison::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, ComparisonOperation op)
410 {
411 return experimental::NEElementwiseComparison::validate(input1, input2, output, op);
412 }
413
run()414 void NEElementwiseComparison::run()
415 {
416 ITensorPack pack;
417 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
418 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
419 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
420 _impl->op->run(pack);
421 }
422
423 // Supported Specializations
424 template class NEElementwiseComparisonStatic<ComparisonOperation::Equal>;
425 template class NEElementwiseComparisonStatic<ComparisonOperation::NotEqual>;
426 template class NEElementwiseComparisonStatic<ComparisonOperation::Greater>;
427 template class NEElementwiseComparisonStatic<ComparisonOperation::GreaterEqual>;
428 template class NEElementwiseComparisonStatic<ComparisonOperation::Less>;
429 template class NEElementwiseComparisonStatic<ComparisonOperation::LessEqual>;
430 } // namespace arm_compute
431