blob: 747bd41dc0377271d443de337cfea5a402f94aa4 [file] [log] [blame]
George Wort5a97b282018-12-21 16:21:04 +00001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2018-2020 Arm Limited.
George Wort5a97b282018-12-21 16:21:04 +00003 *
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/NEON/kernels/NEElementwiseUnaryKernel.h"
25
26#include "arm_compute/core/CPP/Validate.h"
27#include "arm_compute/core/Error.h"
28#include "arm_compute/core/Helpers.h"
George Wort5a97b282018-12-21 16:21:04 +000029#include "arm_compute/core/ITensor.h"
George Wort5a97b282018-12-21 16:21:04 +000030#include "arm_compute/core/NEON/wrapper/wrapper.h"
George Wort5a97b282018-12-21 16:21:04 +000031#include "arm_compute/core/Validate.h"
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010032#include "support/ToolchainSupport.h"
George Wort5a97b282018-12-21 16:21:04 +000033
George Wort5a97b282018-12-21 16:21:04 +000034namespace arm_compute
35{
George Wort5a97b282018-12-21 16:21:04 +000036namespace
37{
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010038template <typename ScalarType>
39inline ScalarType elementwise_op_scalar_imp(ElementWiseUnary op, const ScalarType &a)
George Wort5a97b282018-12-21 16:21:04 +000040{
41 switch(op)
42 {
43 case ElementWiseUnary::RSQRT:
44 return 1 / sqrt(a);
45 case ElementWiseUnary::EXP:
46 return std::exp(a);
Usama Ariff6e475c2019-05-10 12:06:28 +010047 case ElementWiseUnary::NEG:
48 return -a;
Usama Arifc255aa72019-05-13 16:26:29 +010049 case ElementWiseUnary::LOG:
50 return std::log(a);
Manuel Bottini6ac59922019-05-15 14:06:02 +010051 case ElementWiseUnary::ABS:
52 return std::abs(a);
Usama Arif0a5a57a2019-05-23 14:20:33 +010053 case ElementWiseUnary::ROUND:
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010054 return support::cpp11::nearbyint(a);
Manuel Bottinied753262019-05-15 15:30:47 +010055 case ElementWiseUnary::SIN:
56 return std::sin(a);
George Wort5a97b282018-12-21 16:21:04 +000057 default:
58 ARM_COMPUTE_ERROR("NOT_SUPPORTED!");
59 }
60}
61
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010062template <typename ScalarType, typename VectorType>
63inline VectorType elementwise_op_imp(ElementWiseUnary op, const VectorType &a)
George Wort5a97b282018-12-21 16:21:04 +000064{
65 switch(op)
66 {
67 case ElementWiseUnary::RSQRT:
68 return wrapper::vinvsqrt(a);
69 case ElementWiseUnary::EXP:
70 return wrapper::vexpq(a);
Usama Ariff6e475c2019-05-10 12:06:28 +010071 case ElementWiseUnary::NEG:
72 return wrapper::vneg(a);
Usama Arifc255aa72019-05-13 16:26:29 +010073 case ElementWiseUnary::LOG:
74 return wrapper::vlog(a);
Manuel Bottini6ac59922019-05-15 14:06:02 +010075 case ElementWiseUnary::ABS:
76 return wrapper::vabs(a);
Usama Arif0a5a57a2019-05-23 14:20:33 +010077 case ElementWiseUnary::ROUND:
78 return wrapper::vround(a);
Manuel Bottinied753262019-05-15 15:30:47 +010079 case ElementWiseUnary::SIN:
80 return wrapper::vsin(a);
George Wort5a97b282018-12-21 16:21:04 +000081 default:
82 ARM_COMPUTE_ERROR("NOT_SUPPORTED!");
83 }
84}
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010085} // namespace
George Wort5a97b282018-12-21 16:21:04 +000086
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010087template <typename ScalarType>
88void NEElementwiseUnaryKernel::elementwise_op(const Window &window)
George Wort5a97b282018-12-21 16:21:04 +000089{
90 const int window_step_x = 16 / sizeof(ScalarType);
91 const auto window_start_x = static_cast<int>(window.x().start());
92 const auto window_end_x = static_cast<int>(window.x().end());
93
94 Window win = window;
95 win.set(Window::DimX, Window::Dimension(0, 1, 1));
96
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010097 Iterator input(_input, win);
98 Iterator output(_output, win);
George Wort5a97b282018-12-21 16:21:04 +000099
Michalis Spyroua4f378d2019-04-26 14:54:54 +0100100 execute_window_loop(win, [&](const Coordinates &)
George Wort5a97b282018-12-21 16:21:04 +0000101 {
102 auto output_ptr = reinterpret_cast<ScalarType *>(output.ptr());
103 const auto input_ptr = reinterpret_cast<const ScalarType *>(input.ptr());
104
105 int x = window_start_x;
106 for(; x <= window_end_x - window_step_x; x += window_step_x)
107 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100108 wrapper::vstore(output_ptr + x, elementwise_op_imp<ScalarType>(_op, wrapper::vloadq(input_ptr + x)));
George Wort5a97b282018-12-21 16:21:04 +0000109 }
110 for(; x < window_end_x; ++x)
111 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100112 *(output_ptr + x) = elementwise_op_scalar_imp(_op, *(input_ptr + x));
George Wort5a97b282018-12-21 16:21:04 +0000113 }
114 },
115 input, output);
116}
117
George Wort5a97b282018-12-21 16:21:04 +0000118NEElementwiseUnaryKernel::NEElementwiseUnaryKernel()
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100119 : _func(nullptr), _input(nullptr), _output(nullptr), _op()
George Wort5a97b282018-12-21 16:21:04 +0000120{
121}
122
123void NEElementwiseUnaryKernel::configure(ElementWiseUnary op, const ITensor *input, ITensor *output)
124{
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100125 ARM_COMPUTE_ERROR_THROW_ON(validate(op, input->info(), output->info()));
George Wort5a97b282018-12-21 16:21:04 +0000126 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
127
128 // Configure kernel window
129 const std::pair<TensorShape, ValidRegion> broadcast_pair = ITensorInfo::broadcast_shape_and_valid_region(*input->info());
130 const TensorShape &out_shape = broadcast_pair.first;
131 const ValidRegion &valid_region = broadcast_pair.second;
132
133 // Auto initialize output if not initialized
134 auto_init_if_empty(*output->info(), out_shape, 1, input->info()->data_type());
135
136 Window win = calculate_max_window(valid_region);
137
138 _input = input;
139 _output = output;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100140 _op = op;
George Wort5a97b282018-12-21 16:21:04 +0000141
142 INEKernel::configure(win);
143
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100144 switch(input->info()->data_type())
George Wort5a97b282018-12-21 16:21:04 +0000145 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100146 case DataType::F32:
147 _func = &NEElementwiseUnaryKernel::elementwise_op<float>;
George Wort5a97b282018-12-21 16:21:04 +0000148 break;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100149#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
150 case DataType::F16:
151 _func = &NEElementwiseUnaryKernel::elementwise_op<float16_t>;
152#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
George Wort5a97b282018-12-21 16:21:04 +0000153 break;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100154 case DataType::S32:
155 _func = &NEElementwiseUnaryKernel::elementwise_op<int32_t>;
Manuel Bottinied753262019-05-15 15:30:47 +0100156 break;
George Wort5a97b282018-12-21 16:21:04 +0000157 default:
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100158 ARM_COMPUTE_ERROR("DataType not supported");
George Wort5a97b282018-12-21 16:21:04 +0000159 }
160}
161
George Wort5a97b282018-12-21 16:21:04 +0000162Status NEElementwiseUnaryKernel::validate(ElementWiseUnary op, const ITensorInfo *input, const ITensorInfo *output)
163{
George Wort5a97b282018-12-21 16:21:04 +0000164 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100165 ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(input);
166 switch(op)
167 {
168 case ElementWiseUnary::EXP:
169 case ElementWiseUnary::RSQRT:
170 case ElementWiseUnary::LOG:
171 case ElementWiseUnary::ROUND:
172 case ElementWiseUnary::SIN:
173 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32);
174 break;
175 case ElementWiseUnary::NEG:
176 case ElementWiseUnary::ABS:
177 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32, DataType::S32);
178 break;
179 default:
180 ARM_COMPUTE_ERROR("ElementWiseUnary operation not supported");
181 }
182 // Validate in case of configured output
183 if(output->total_size() > 0)
184 {
185 ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
186 }
187
George Wort5a97b282018-12-21 16:21:04 +0000188 return Status{};
189}
190
191void NEElementwiseUnaryKernel::run(const Window &window, const ThreadInfo &info)
192{
193 ARM_COMPUTE_UNUSED(info);
194 ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
195 ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100196 ARM_COMPUTE_ERROR_ON(_func == nullptr);
197 (this->*_func)(window);
George Wort5a97b282018-12-21 16:21:04 +0000198}
199} // namespace arm_compute