blob: 8e4b7eda3023f15af83791db00e3e1333f4dfd23 [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
George Wort5a97b282018-12-21 16:21:04 +000026#include "arm_compute/core/Error.h"
27#include "arm_compute/core/Helpers.h"
George Wort5a97b282018-12-21 16:21:04 +000028#include "arm_compute/core/ITensor.h"
George Wort5a97b282018-12-21 16:21:04 +000029#include "arm_compute/core/Validate.h"
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010030#include "src/core/CPP/Validate.h"
Georgios Pinitasddb93bb2020-10-02 16:38:59 +010031#include "src/core/NEON/wrapper/wrapper.h"
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010032#include "src/core/helpers/AutoConfiguration.h"
33#include "src/core/helpers/WindowHelpers.h"
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010034#include "support/ToolchainSupport.h"
George Wort5a97b282018-12-21 16:21:04 +000035
George Wort5a97b282018-12-21 16:21:04 +000036namespace arm_compute
37{
George Wort5a97b282018-12-21 16:21:04 +000038namespace
39{
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010040template <typename ScalarType>
41inline ScalarType elementwise_op_scalar_imp(ElementWiseUnary op, const ScalarType &a)
George Wort5a97b282018-12-21 16:21:04 +000042{
43 switch(op)
44 {
45 case ElementWiseUnary::RSQRT:
46 return 1 / sqrt(a);
47 case ElementWiseUnary::EXP:
48 return std::exp(a);
Usama Ariff6e475c2019-05-10 12:06:28 +010049 case ElementWiseUnary::NEG:
50 return -a;
Usama Arifc255aa72019-05-13 16:26:29 +010051 case ElementWiseUnary::LOG:
52 return std::log(a);
Manuel Bottini6ac59922019-05-15 14:06:02 +010053 case ElementWiseUnary::ABS:
54 return std::abs(a);
Usama Arif0a5a57a2019-05-23 14:20:33 +010055 case ElementWiseUnary::ROUND:
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010056 return support::cpp11::nearbyint(a);
Manuel Bottinied753262019-05-15 15:30:47 +010057 case ElementWiseUnary::SIN:
58 return std::sin(a);
George Wort5a97b282018-12-21 16:21:04 +000059 default:
60 ARM_COMPUTE_ERROR("NOT_SUPPORTED!");
61 }
62}
63
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010064template <typename ScalarType, typename VectorType>
65inline VectorType elementwise_op_imp(ElementWiseUnary op, const VectorType &a)
George Wort5a97b282018-12-21 16:21:04 +000066{
67 switch(op)
68 {
69 case ElementWiseUnary::RSQRT:
70 return wrapper::vinvsqrt(a);
71 case ElementWiseUnary::EXP:
72 return wrapper::vexpq(a);
Usama Ariff6e475c2019-05-10 12:06:28 +010073 case ElementWiseUnary::NEG:
74 return wrapper::vneg(a);
Usama Arifc255aa72019-05-13 16:26:29 +010075 case ElementWiseUnary::LOG:
76 return wrapper::vlog(a);
Manuel Bottini6ac59922019-05-15 14:06:02 +010077 case ElementWiseUnary::ABS:
78 return wrapper::vabs(a);
Usama Arif0a5a57a2019-05-23 14:20:33 +010079 case ElementWiseUnary::ROUND:
80 return wrapper::vround(a);
Manuel Bottinied753262019-05-15 15:30:47 +010081 case ElementWiseUnary::SIN:
82 return wrapper::vsin(a);
George Wort5a97b282018-12-21 16:21:04 +000083 default:
84 ARM_COMPUTE_ERROR("NOT_SUPPORTED!");
85 }
86}
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010087} // namespace
George Wort5a97b282018-12-21 16:21:04 +000088
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010089template <typename ScalarType>
90void NEElementwiseUnaryKernel::elementwise_op(const Window &window)
George Wort5a97b282018-12-21 16:21:04 +000091{
92 const int window_step_x = 16 / sizeof(ScalarType);
93 const auto window_start_x = static_cast<int>(window.x().start());
94 const auto window_end_x = static_cast<int>(window.x().end());
95
96 Window win = window;
97 win.set(Window::DimX, Window::Dimension(0, 1, 1));
98
Michalis Spyrou18e20ff2020-05-06 17:03:59 +010099 Iterator input(_input, win);
100 Iterator output(_output, win);
George Wort5a97b282018-12-21 16:21:04 +0000101
Michalis Spyroua4f378d2019-04-26 14:54:54 +0100102 execute_window_loop(win, [&](const Coordinates &)
George Wort5a97b282018-12-21 16:21:04 +0000103 {
104 auto output_ptr = reinterpret_cast<ScalarType *>(output.ptr());
105 const auto input_ptr = reinterpret_cast<const ScalarType *>(input.ptr());
106
107 int x = window_start_x;
108 for(; x <= window_end_x - window_step_x; x += window_step_x)
109 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100110 wrapper::vstore(output_ptr + x, elementwise_op_imp<ScalarType>(_op, wrapper::vloadq(input_ptr + x)));
George Wort5a97b282018-12-21 16:21:04 +0000111 }
112 for(; x < window_end_x; ++x)
113 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100114 *(output_ptr + x) = elementwise_op_scalar_imp(_op, *(input_ptr + x));
George Wort5a97b282018-12-21 16:21:04 +0000115 }
116 },
117 input, output);
118}
119
George Wort5a97b282018-12-21 16:21:04 +0000120NEElementwiseUnaryKernel::NEElementwiseUnaryKernel()
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100121 : _func(nullptr), _input(nullptr), _output(nullptr), _op()
George Wort5a97b282018-12-21 16:21:04 +0000122{
123}
124
125void NEElementwiseUnaryKernel::configure(ElementWiseUnary op, const ITensor *input, ITensor *output)
126{
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100127 ARM_COMPUTE_ERROR_THROW_ON(validate(op, input->info(), output->info()));
George Wort5a97b282018-12-21 16:21:04 +0000128 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
129
130 // Configure kernel window
131 const std::pair<TensorShape, ValidRegion> broadcast_pair = ITensorInfo::broadcast_shape_and_valid_region(*input->info());
132 const TensorShape &out_shape = broadcast_pair.first;
133 const ValidRegion &valid_region = broadcast_pair.second;
134
135 // Auto initialize output if not initialized
136 auto_init_if_empty(*output->info(), out_shape, 1, input->info()->data_type());
137
138 Window win = calculate_max_window(valid_region);
139
140 _input = input;
141 _output = output;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100142 _op = op;
George Wort5a97b282018-12-21 16:21:04 +0000143
144 INEKernel::configure(win);
145
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100146 switch(input->info()->data_type())
George Wort5a97b282018-12-21 16:21:04 +0000147 {
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100148 case DataType::F32:
149 _func = &NEElementwiseUnaryKernel::elementwise_op<float>;
George Wort5a97b282018-12-21 16:21:04 +0000150 break;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100151#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
152 case DataType::F16:
153 _func = &NEElementwiseUnaryKernel::elementwise_op<float16_t>;
154#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
George Wort5a97b282018-12-21 16:21:04 +0000155 break;
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100156 case DataType::S32:
157 _func = &NEElementwiseUnaryKernel::elementwise_op<int32_t>;
Manuel Bottinied753262019-05-15 15:30:47 +0100158 break;
George Wort5a97b282018-12-21 16:21:04 +0000159 default:
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100160 ARM_COMPUTE_ERROR("DataType not supported");
George Wort5a97b282018-12-21 16:21:04 +0000161 }
162}
163
George Wort5a97b282018-12-21 16:21:04 +0000164Status NEElementwiseUnaryKernel::validate(ElementWiseUnary op, const ITensorInfo *input, const ITensorInfo *output)
165{
George Wort5a97b282018-12-21 16:21:04 +0000166 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100167 ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(input);
168 switch(op)
169 {
170 case ElementWiseUnary::EXP:
171 case ElementWiseUnary::RSQRT:
172 case ElementWiseUnary::LOG:
173 case ElementWiseUnary::ROUND:
174 case ElementWiseUnary::SIN:
175 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32);
176 break;
177 case ElementWiseUnary::NEG:
178 case ElementWiseUnary::ABS:
179 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32, DataType::S32);
180 break;
181 default:
182 ARM_COMPUTE_ERROR("ElementWiseUnary operation not supported");
183 }
184 // Validate in case of configured output
185 if(output->total_size() > 0)
186 {
187 ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
188 }
189
George Wort5a97b282018-12-21 16:21:04 +0000190 return Status{};
191}
192
193void NEElementwiseUnaryKernel::run(const Window &window, const ThreadInfo &info)
194{
195 ARM_COMPUTE_UNUSED(info);
196 ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
197 ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
Michalis Spyrou18e20ff2020-05-06 17:03:59 +0100198 ARM_COMPUTE_ERROR_ON(_func == nullptr);
199 (this->*_func)(window);
George Wort5a97b282018-12-21 16:21:04 +0000200}
201} // namespace arm_compute