1 /*
2 * Copyright (c) 2018-2021 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/runtime/NEON/functions/NEElementwiseOperations.h"
25 #include "arm_compute/core/Validate.h"
26 #include "src/cpu/operators/CpuElementwise.h"
27
28 #include "arm_compute/core/ITensor.h"
29
30 #include <utility>
31
32 namespace arm_compute
33 {
34 struct NEElementwiseMax::Impl
35 {
36 const ITensor *src_0{ nullptr };
37 const ITensor *src_1{ nullptr };
38 ITensor *dst{ nullptr };
39 std::unique_ptr<cpu::CpuElementwiseMax> op{ nullptr };
40 };
41
NEElementwiseMax()42 NEElementwiseMax::NEElementwiseMax()
43 : _impl(std::make_unique<Impl>())
44 {
45 }
46 NEElementwiseMax::NEElementwiseMax(NEElementwiseMax &&) = default;
47 NEElementwiseMax &NEElementwiseMax::operator=(NEElementwiseMax &&) = default;
48 NEElementwiseMax::~NEElementwiseMax() = default;
49
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)50 void NEElementwiseMax::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
51 {
52 ARM_COMPUTE_UNUSED(act_info);
53 _impl->src_0 = input1;
54 _impl->src_1 = input2;
55 _impl->dst = output;
56 _impl->op = std::make_unique<cpu::CpuElementwiseMax>();
57 _impl->op->configure(input1->info(), input2->info(), output->info());
58 }
59
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)60 Status NEElementwiseMax::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
61 {
62 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
63 return cpu::CpuElementwiseMax::validate(input1, input2, output);
64 }
65
run()66 void NEElementwiseMax::run()
67 {
68 ITensorPack pack;
69 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
70 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
71 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
72 _impl->op->run(pack);
73 }
74
75 struct NEElementwiseMin::Impl
76 {
77 const ITensor *src_0{ nullptr };
78 const ITensor *src_1{ nullptr };
79 ITensor *dst{ nullptr };
80 std::unique_ptr<cpu::CpuElementwiseMin> op{ nullptr };
81 };
82
NEElementwiseMin()83 NEElementwiseMin::NEElementwiseMin()
84 : _impl(std::make_unique<Impl>())
85 {
86 }
87 NEElementwiseMin::NEElementwiseMin(NEElementwiseMin &&) = default;
88 NEElementwiseMin &NEElementwiseMin::operator=(NEElementwiseMin &&) = default;
89 NEElementwiseMin::~NEElementwiseMin() = default;
90
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)91 void NEElementwiseMin::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
92 {
93 ARM_COMPUTE_UNUSED(act_info);
94 _impl->src_0 = input1;
95 _impl->src_1 = input2;
96 _impl->dst = output;
97 _impl->op = std::make_unique<cpu::CpuElementwiseMin>();
98 _impl->op->configure(input1->info(), input2->info(), output->info());
99 }
100
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)101 Status NEElementwiseMin::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
102 {
103 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
104 return cpu::CpuElementwiseMin::validate(input1, input2, output);
105 }
106
run()107 void NEElementwiseMin::run()
108 {
109 ITensorPack pack;
110 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
111 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
112 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
113 _impl->op->run(pack);
114 }
115
116 struct NEElementwiseSquaredDiff::Impl
117 {
118 const ITensor *src_0{ nullptr };
119 const ITensor *src_1{ nullptr };
120 ITensor *dst{ nullptr };
121 std::unique_ptr<cpu::CpuElementwiseSquaredDiff> op{ nullptr };
122 };
123
NEElementwiseSquaredDiff()124 NEElementwiseSquaredDiff::NEElementwiseSquaredDiff()
125 : _impl(std::make_unique<Impl>())
126 {
127 }
128 NEElementwiseSquaredDiff::NEElementwiseSquaredDiff(NEElementwiseSquaredDiff &&) = default;
129 NEElementwiseSquaredDiff &NEElementwiseSquaredDiff::operator=(NEElementwiseSquaredDiff &&) = default;
130 NEElementwiseSquaredDiff::~NEElementwiseSquaredDiff() = default;
131
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)132 void NEElementwiseSquaredDiff::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
133 {
134 ARM_COMPUTE_UNUSED(act_info);
135 _impl->src_0 = input1;
136 _impl->src_1 = input2;
137 _impl->dst = output;
138 _impl->op = std::make_unique<cpu::CpuElementwiseSquaredDiff>();
139 _impl->op->configure(input1->info(), input2->info(), output->info());
140 }
141
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)142 Status NEElementwiseSquaredDiff::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
143 {
144 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
145 return cpu::CpuElementwiseSquaredDiff::validate(input1, input2, output);
146 }
147
run()148 void NEElementwiseSquaredDiff::run()
149 {
150 ITensorPack pack;
151 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
152 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
153 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
154 _impl->op->run(pack);
155 }
156
157 struct NEElementwiseDivision::Impl
158 {
159 const ITensor *src_0{ nullptr };
160 const ITensor *src_1{ nullptr };
161 ITensor *dst{ nullptr };
162 std::unique_ptr<cpu::CpuElementwiseDivision> op{ nullptr };
163 };
164
NEElementwiseDivision()165 NEElementwiseDivision::NEElementwiseDivision()
166 : _impl(std::make_unique<Impl>())
167 {
168 }
169 NEElementwiseDivision::NEElementwiseDivision(NEElementwiseDivision &&) = default;
170 NEElementwiseDivision &NEElementwiseDivision::operator=(NEElementwiseDivision &&) = default;
171 NEElementwiseDivision::~NEElementwiseDivision() = default;
172
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)173 void NEElementwiseDivision::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
174 {
175 ARM_COMPUTE_UNUSED(act_info);
176 _impl->src_0 = input1;
177 _impl->src_1 = input2;
178 _impl->dst = output;
179 _impl->op = std::make_unique<cpu::CpuElementwiseDivision>();
180 _impl->op->configure(input1->info(), input2->info(), output->info());
181 }
182
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)183 Status NEElementwiseDivision::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
184 {
185 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
186 return cpu::CpuElementwiseDivision::validate(input1, input2, output);
187 }
188
run()189 void NEElementwiseDivision::run()
190 {
191 ITensorPack pack;
192 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
193 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
194 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
195 _impl->op->run(pack);
196 }
197
198 struct NEElementwisePower::Impl
199 {
200 const ITensor *src_0{ nullptr };
201 const ITensor *src_1{ nullptr };
202 ITensor *dst{ nullptr };
203 std::unique_ptr<cpu::CpuElementwisePower> op{ nullptr };
204 };
205
NEElementwisePower()206 NEElementwisePower::NEElementwisePower()
207 : _impl(std::make_unique<Impl>())
208 {
209 }
210 NEElementwisePower::NEElementwisePower(NEElementwisePower &&) = default;
211 NEElementwisePower &NEElementwisePower::operator=(NEElementwisePower &&) = default;
212 NEElementwisePower::~NEElementwisePower() = default;
213
configure(ITensor * input1,ITensor * input2,ITensor * output,const ActivationLayerInfo & act_info)214 void NEElementwisePower::configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info)
215 {
216 ARM_COMPUTE_UNUSED(act_info);
217 _impl->src_0 = input1;
218 _impl->src_1 = input2;
219 _impl->dst = output;
220 _impl->op = std::make_unique<cpu::CpuElementwisePower>();
221 _impl->op->configure(input1->info(), input2->info(), output->info());
222 }
223
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,const ActivationLayerInfo & act_info)224 Status NEElementwisePower::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, const ActivationLayerInfo &act_info)
225 {
226 ARM_COMPUTE_RETURN_ERROR_ON(act_info.enabled());
227 return cpu::CpuElementwisePower::validate(input1, input2, output);
228 }
229
run()230 void NEElementwisePower::run()
231 {
232 ITensorPack pack;
233 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
234 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
235 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
236 _impl->op->run(pack);
237 }
238
239 template <ComparisonOperation COP>
240 struct NEElementwiseComparisonStatic<COP>::Impl
241 {
242 const ITensor *src_0{ nullptr };
243 const ITensor *src_1{ nullptr };
244 ITensor *dst{ nullptr };
245 std::unique_ptr<cpu::CpuElementwiseComparisonStatic<COP>> op{ nullptr };
246 };
247
248 template <ComparisonOperation COP>
NEElementwiseComparisonStatic()249 NEElementwiseComparisonStatic<COP>::NEElementwiseComparisonStatic()
250 : _impl(std::make_unique<Impl>())
251 {
252 }
253 template <ComparisonOperation COP>
254 NEElementwiseComparisonStatic<COP>::NEElementwiseComparisonStatic(NEElementwiseComparisonStatic &&) = default;
255 template <ComparisonOperation COP>
256 NEElementwiseComparisonStatic<COP> &NEElementwiseComparisonStatic<COP>::operator=(NEElementwiseComparisonStatic &&) = default;
257 template <ComparisonOperation COP>
258 NEElementwiseComparisonStatic<COP>::~NEElementwiseComparisonStatic() = default;
259
260 template <ComparisonOperation COP>
configure(ITensor * input1,ITensor * input2,ITensor * output)261 void NEElementwiseComparisonStatic<COP>::configure(ITensor *input1, ITensor *input2, ITensor *output)
262 {
263 _impl->src_0 = input1;
264 _impl->src_1 = input2;
265 _impl->dst = output;
266 _impl->op = std::make_unique<cpu::CpuElementwiseComparisonStatic<COP>>();
267 _impl->op->configure(input1->info(), input2->info(), output->info());
268 }
269
270 template <ComparisonOperation COP>
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output)271 Status NEElementwiseComparisonStatic<COP>::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output)
272 {
273 return cpu::CpuElementwiseComparisonStatic<COP>::validate(input1, input2, output);
274 }
275
276 template <ComparisonOperation COP>
run()277 void NEElementwiseComparisonStatic<COP>::run()
278 {
279 ITensorPack pack;
280 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
281 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
282 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
283 _impl->op->run(pack);
284 }
285
286 struct NEElementwiseComparison::Impl
287 {
288 const ITensor *src_0{ nullptr };
289 const ITensor *src_1{ nullptr };
290 ITensor *dst{ nullptr };
291 std::unique_ptr<cpu::CpuElementwiseComparison> op{ nullptr };
292 };
293
NEElementwiseComparison()294 NEElementwiseComparison::NEElementwiseComparison()
295 : _impl(std::make_unique<Impl>())
296 {
297 }
298 NEElementwiseComparison::NEElementwiseComparison(NEElementwiseComparison &&) = default;
299 NEElementwiseComparison &NEElementwiseComparison::operator=(NEElementwiseComparison &&) = default;
300 NEElementwiseComparison::~NEElementwiseComparison() = default;
301
configure(ITensor * input1,ITensor * input2,ITensor * output,ComparisonOperation op)302 void NEElementwiseComparison::configure(ITensor *input1, ITensor *input2, ITensor *output, ComparisonOperation op)
303 {
304 _impl->src_0 = input1;
305 _impl->src_1 = input2;
306 _impl->dst = output;
307 _impl->op = std::make_unique<cpu::CpuElementwiseComparison>();
308 _impl->op->configure(input1->info(), input2->info(), output->info(), op);
309 }
310
validate(const ITensorInfo * input1,const ITensorInfo * input2,const ITensorInfo * output,ComparisonOperation op)311 Status NEElementwiseComparison::validate(const ITensorInfo *input1, const ITensorInfo *input2, const ITensorInfo *output, ComparisonOperation op)
312 {
313 return cpu::CpuElementwiseComparison::validate(input1, input2, output, op);
314 }
315
run()316 void NEElementwiseComparison::run()
317 {
318 ITensorPack pack;
319 pack.add_tensor(TensorType::ACL_SRC_0, _impl->src_0);
320 pack.add_tensor(TensorType::ACL_SRC_1, _impl->src_1);
321 pack.add_tensor(TensorType::ACL_DST, _impl->dst);
322 _impl->op->run(pack);
323 }
324
325 // Supported Specializations
326 template class NEElementwiseComparisonStatic<ComparisonOperation::Equal>;
327 template class NEElementwiseComparisonStatic<ComparisonOperation::NotEqual>;
328 template class NEElementwiseComparisonStatic<ComparisonOperation::Greater>;
329 template class NEElementwiseComparisonStatic<ComparisonOperation::GreaterEqual>;
330 template class NEElementwiseComparisonStatic<ComparisonOperation::Less>;
331 template class NEElementwiseComparisonStatic<ComparisonOperation::LessEqual>;
332 } // namespace arm_compute
333