From 7249f154c2ec029f9b8c91f2bb845abe6590f7ed Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Fri, 22 Jan 2021 11:55:03 +0000 Subject: Rename functions/classes for elementwise unary operations * Create CpuElementwiseUnary operator * Rename kernel classes * Make the kernels stateless Partially implements: COMPMID-4003 Change-Id: Ie0440cd01d4924847d6991b4df7ccaf311439297 Signed-off-by: Sang-Hoon Park Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/4912 Tested-by: Arm Jenkins Reviewed-by: Michele Di Giorgio Reviewed-by: Georgios Pinitas Comments-Addressed: Arm Jenkins --- Android.bp | 3 +- .../NEON/functions/NEElementwiseUnaryLayer.h | 162 +++++-------------- docs/00_introduction.dox | 4 +- src/core/NEON/NEKernels.h | 1 - src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp | 172 -------------------- src/core/NEON/kernels/NEElementwiseUnaryKernel.h | 94 ----------- .../elementwise/impl/elementwise_unary_list.h | 116 -------------- .../elementwise/impl/elementwise_unary_list.h | 111 ------------- src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp | 176 +++++++++++++++++++++ src/core/cpu/kernels/CpuElementwiseUnaryKernel.h | 90 +++++++++++ .../elementwise/neon/elementwise_unary_list.h | 116 ++++++++++++++ .../elementwise/sve/elementwise_unary_list.h | 111 +++++++++++++ .../NEON/functions/NEElementwiseUnaryLayer.cpp | 105 +++++------- src/runtime/cpu/operators/CpuElementwiseUnary.cpp | 45 ++++++ src/runtime/cpu/operators/CpuElementwiseUnary.h | 58 +++++++ 15 files changed, 677 insertions(+), 687 deletions(-) delete mode 100644 src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp delete mode 100644 src/core/NEON/kernels/NEElementwiseUnaryKernel.h delete mode 100644 src/core/NEON/kernels/elementwise/impl/elementwise_unary_list.h delete mode 100644 src/core/SVE/kernels/elementwise/impl/elementwise_unary_list.h create mode 100644 src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp create mode 100644 src/core/cpu/kernels/CpuElementwiseUnaryKernel.h create mode 100644 src/core/cpu/kernels/elementwise/neon/elementwise_unary_list.h create mode 100644 src/core/cpu/kernels/elementwise/sve/elementwise_unary_list.h create mode 100644 src/runtime/cpu/operators/CpuElementwiseUnary.cpp create mode 100644 src/runtime/cpu/operators/CpuElementwiseUnary.h diff --git a/Android.bp b/Android.bp index 6984bbe7ea..8a596cd87b 100644 --- a/Android.bp +++ b/Android.bp @@ -245,7 +245,6 @@ cc_library_static { "src/core/NEON/kernels/NEDilateKernel.cpp", "src/core/NEON/kernels/NEDirectConvolutionLayerKernel.cpp", "src/core/NEON/kernels/NEDirectConvolutionLayerOutputStageKernel.cpp", - "src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp", "src/core/NEON/kernels/NEErodeKernel.cpp", "src/core/NEON/kernels/NEFFTDigitReverseKernel.cpp", "src/core/NEON/kernels/NEFFTRadixStageKernel.cpp", @@ -409,6 +408,7 @@ cc_library_static { "src/core/cpu/kernels/CpuConcatenateWidthKernel.cpp", "src/core/cpu/kernels/CpuCopyKernel.cpp", "src/core/cpu/kernels/CpuElementwiseKernel.cpp", + "src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp", "src/core/cpu/kernels/CpuFillKernel.cpp", "src/core/cpu/kernels/CpuFloorKernel.cpp", "src/core/cpu/kernels/CpuPermuteKernel.cpp", @@ -788,6 +788,7 @@ cc_library_static { "src/runtime/cpu/operators/CpuConcatenate.cpp", "src/runtime/cpu/operators/CpuCopy.cpp", "src/runtime/cpu/operators/CpuElementwise.cpp", + "src/runtime/cpu/operators/CpuElementwiseUnary.cpp", "src/runtime/cpu/operators/CpuFill.cpp", "src/runtime/cpu/operators/CpuFloor.cpp", "src/runtime/cpu/operators/CpuPermute.cpp", diff --git a/arm_compute/runtime/NEON/functions/NEElementwiseUnaryLayer.h b/arm_compute/runtime/NEON/functions/NEElementwiseUnaryLayer.h index 46a7316705..e79e8696d9 100644 --- a/arm_compute/runtime/NEON/functions/NEElementwiseUnaryLayer.h +++ b/arm_compute/runtime/NEON/functions/NEElementwiseUnaryLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 Arm Limited. + * Copyright (c) 2018-2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -25,151 +25,63 @@ #define ARM_COMPUTE_NEELEMENTWISEUNARYLAYER_H #include "arm_compute/core/Error.h" -#include "arm_compute/runtime/NEON/INESimpleFunctionNoBorder.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/IFunction.h" +#include "src/core/common/Macros.h" + +#include namespace arm_compute { class ITensor; class ITensorInfo; - -/** Basic function to perform inverse square root on an input tensor. */ -class NERsqrtLayer : public INESimpleFunctionNoBorder +/** Basic function to perform unary elementwise operations */ +template +class NEElementwiseUnaryLayer : public IFunction { public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NERsqrtLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; - -/** Basic function to perform exponential on an input tensor. */ -class NEExpLayer : public INESimpleFunctionNoBorder -{ -public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NEExpLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; - -/** Basic function to negate an input tensor. */ -class NENegLayer : public INESimpleFunctionNoBorder -{ -public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32/S32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NENegLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32/S32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; + /** Default Constructor */ + NEElementwiseUnaryLayer(); + /** Default Destructor */ + ~NEElementwiseUnaryLayer(); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NEElementwiseUnaryLayer(const NEElementwiseUnaryLayer &) = delete; + /** Default move constructor */ + NEElementwiseUnaryLayer(NEElementwiseUnaryLayer &&); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NEElementwiseUnaryLayer &operator=(const NEElementwiseUnaryLayer &) = delete; + /** Default move assignment operator */ + NEElementwiseUnaryLayer &operator=(NEElementwiseUnaryLayer &&); -/** Basic function to compute the natural logarithm of an input tensor. */ -class NELogLayer : public INESimpleFunctionNoBorder -{ -public: /** Initialize the function * - * @param[in] input Input tensor. Data types supported: F16/F32. - * @param[out] output Output tensor. Data types supported: same as @p input. + * @param[in] input Input tensor. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. + * @param[out] output Output tensor. Data types supported: Same as @p input. */ void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NELogLayer + /** Static function to check if given info will lead to a valid configuration * - * @param[in] input First tensor input info. Data types supported: F16/F32. + * @param[in] input Input tensor info. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. * @param[in] output Output tensor info. Data types supported: Same as @p input. * * @return a status */ static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; + // Inherited methods overridden: + void run() override; -/** Basic function to compute the absolute value of an input tensor. */ -class NEAbsLayer : public INESimpleFunctionNoBorder -{ -public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32/S32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NEAbsLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32/S32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); +private: + struct Impl; + std::unique_ptr _impl; }; -/** Basic function to compute the round value elementwise of an input tensor. */ -class NERoundLayer : public INESimpleFunctionNoBorder -{ -public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NERoundLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; +using NERsqrtLayer = NEElementwiseUnaryLayer; +using NEExpLayer = NEElementwiseUnaryLayer; +using NENegLayer = NEElementwiseUnaryLayer; +using NELogLayer = NEElementwiseUnaryLayer; +using NEAbsLayer = NEElementwiseUnaryLayer; +using NERoundLayer = NEElementwiseUnaryLayer; +using NESinLayer = NEElementwiseUnaryLayer; -/** Basic function to compute the sine of an input tensor. */ -class NESinLayer : public INESimpleFunctionNoBorder -{ -public: - /** Initialize the function - * - * @param[in] input Input tensor. Data types supported: F16/F32. - * @param[out] output Output tensor. Data types supported: same as @p input. - */ - void configure(const ITensor *input, ITensor *output); - /** Static function to check if given info will lead to a valid configuration of @ref NESinLayer - * - * @param[in] input First tensor input info. Data types supported: F16/F32. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a status - */ - static Status validate(const ITensorInfo *input, const ITensorInfo *output); -}; } // namespace arm_compute #endif /* ARM_COMPUTE_NEELEMENTWISEUNARYLAYER_H */ diff --git a/docs/00_introduction.dox b/docs/00_introduction.dox index f2dddbea6f..3c89cfddcb 100644 --- a/docs/00_introduction.dox +++ b/docs/00_introduction.dox @@ -98,7 +98,7 @@ v21.02 Public major release - @ref NEBatchNormalizationLayerKernel - @ref NELogits1DSoftmaxKernel - @ref NELogits1DMaxKernel - - @ref NEElementwiseUnaryKernel + - NEElementwiseUnaryKernel - Remove functions: - NELocallyConnectedLayer / CLLocallyConnectedLayer - NEIm2Col @@ -830,7 +830,7 @@ v19.02 Public major release - @ref NESlice - @ref NEUnstack - @ref NEStridedSliceKernel / @ref NEStridedSlice - - @ref NEElementwiseUnaryKernel + - NEElementwiseUnaryKernel - @ref NERsqrtLayer - @ref NEExpLayer - @ref NEReverseKernel / @ref NEReverse diff --git a/src/core/NEON/NEKernels.h b/src/core/NEON/NEKernels.h index c009a6d3af..87eec38605 100644 --- a/src/core/NEON/NEKernels.h +++ b/src/core/NEON/NEKernels.h @@ -54,7 +54,6 @@ #include "src/core/NEON/kernels/NEDilateKernel.h" #include "src/core/NEON/kernels/NEDirectConvolutionLayerKernel.h" #include "src/core/NEON/kernels/NEDirectConvolutionLayerOutputStageKernel.h" -#include "src/core/NEON/kernels/NEElementwiseUnaryKernel.h" #include "src/core/NEON/kernels/NEErodeKernel.h" #include "src/core/NEON/kernels/NEFFTDigitReverseKernel.h" #include "src/core/NEON/kernels/NEFFTRadixStageKernel.h" diff --git a/src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp b/src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp deleted file mode 100644 index fdd2aabf60..0000000000 --- a/src/core/NEON/kernels/NEElementwiseUnaryKernel.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2018-2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "src/core/NEON/kernels/NEElementwiseUnaryKernel.h" - -#include "arm_compute/core/Error.h" -#include "arm_compute/core/Helpers.h" -#include "arm_compute/core/ITensor.h" -#include "arm_compute/core/Validate.h" -#include "src/core/CPP/Validate.h" -#include "src/core/NEON/kernels/elementwise/impl/elementwise_unary_list.h" -#include "src/core/SVE/kernels/elementwise/impl/elementwise_unary_list.h" -#include "src/core/common/Registrars.h" -#include "src/core/helpers/AutoConfiguration.h" -#include "src/core/helpers/WindowHelpers.h" -#include "support/ToolchainSupport.h" - -namespace arm_compute -{ -namespace -{ -using ElementwiseUnarySelector = std::add_pointer::type; - -struct ElementwiseUnaryKernel -{ - const char *name; - const ElementwiseUnarySelector is_selected; - NEElementwiseUnaryKernel::ElementwiseUnaryUkernelPtr ukernel; -}; - -static const ElementwiseUnaryKernel available_kernels[] = -{ -#if defined(__ARM_FEATURE_SVE) - { - "fp32_sve_elementwise_unary", - [](DataType dt) { return dt == DataType::F32; }, - REGISTER_FP32_SVE(arm_compute::cpu::elementwise_sve_op), - }, - { - "fp16_sve_elementwise_unary", - [](DataType dt) { return dt == DataType::F16; }, - REGISTER_FP16_SVE(arm_compute::cpu::elementwise_sve_op<__fp16>), - }, - { - "s32_sve_elementwise_unary", - [](DataType dt) { return dt == DataType::S32; }, - REGISTER_INTEGER_SVE(arm_compute::cpu::elementwise_sve_op), - }, -#endif // defined(__ARM_FEATURE_SVE) - { - "fp32_neon_elementwise_unary", - [](DataType dt) { return dt == DataType::F32; }, - REGISTER_FP32_NEON(arm_compute::cpu::elementwise_op), - }, -#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) - { - "fp16_neon_elementwise_unary", - [](DataType dt) { return dt == DataType::F16; }, - REGISTER_FP32_NEON(arm_compute::cpu::elementwise_op<__fp16>), - }, -#endif // defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) - { - "s32_neon_elementwise_unary", - [](DataType dt) { return dt == DataType::S32; }, - REGISTER_INTEGER_NEON(arm_compute::cpu::elementwise_op), - }, -}; - -const ElementwiseUnaryKernel *get_implementation(DataType dt) -{ - for(const auto &uk : available_kernels) - { - if(uk.is_selected(dt)) - { - return &uk; - } - } - return nullptr; -} -} // namespace - -NEElementwiseUnaryKernel::NEElementwiseUnaryKernel() - : _func(nullptr), _input(nullptr), _output(nullptr), _op() -{ -} - -void NEElementwiseUnaryKernel::configure(ElementWiseUnary op, const ITensor *input, ITensor *output) -{ - ARM_COMPUTE_ERROR_THROW_ON(validate(op, input->info(), output->info())); - ARM_COMPUTE_ERROR_ON_NULLPTR(input, output); - - // Configure kernel window - const std::pair broadcast_pair = ITensorInfo::broadcast_shape_and_valid_region(*input->info()); - const TensorShape &out_shape = broadcast_pair.first; - const ValidRegion &valid_region = broadcast_pair.second; - - // Auto initialize output if not initialized - auto_init_if_empty(*output->info(), out_shape, 1, input->info()->data_type()); - - Window win = calculate_max_window(valid_region); - - _input = input; - _output = output; - _op = op; - - INEKernel::configure(win); - - _func = get_implementation(input->info()->data_type())->ukernel; -} - -Status NEElementwiseUnaryKernel::validate(ElementWiseUnary op, const ITensorInfo *input, const ITensorInfo *output) -{ - ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output); - ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(input); - - const auto *uk = get_implementation(input->data_type()); - ARM_COMPUTE_RETURN_ERROR_ON(uk == nullptr || uk->ukernel == nullptr); - - switch(op) - { - case ElementWiseUnary::EXP: - case ElementWiseUnary::RSQRT: - case ElementWiseUnary::LOG: - case ElementWiseUnary::ROUND: - case ElementWiseUnary::SIN: - ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32); - break; - case ElementWiseUnary::NEG: - case ElementWiseUnary::ABS: - ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F16, DataType::F32, DataType::S32); - break; - default: - ARM_COMPUTE_ERROR("ElementWiseUnary operation not supported"); - } - // Validate in case of configured output - if(output->total_size() > 0) - { - ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output); - } - - return Status{}; -} - -void NEElementwiseUnaryKernel::run(const Window &window, const ThreadInfo &info) -{ - ARM_COMPUTE_UNUSED(info); - ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this); - ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window); - ARM_COMPUTE_ERROR_ON(_func == nullptr); - (*_func)(_input, _output, window, _op); -} -} // namespace arm_compute diff --git a/src/core/NEON/kernels/NEElementwiseUnaryKernel.h b/src/core/NEON/kernels/NEElementwiseUnaryKernel.h deleted file mode 100644 index b248e821c3..0000000000 --- a/src/core/NEON/kernels/NEElementwiseUnaryKernel.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2018-2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef ARM_COMPUTE_NEELEMENTWISEUNARYKERNEL_H -#define ARM_COMPUTE_NEELEMENTWISEUNARYKERNEL_H - -#include "arm_compute/core/Types.h" -#include "src/core/NEON/INEKernel.h" - -namespace arm_compute -{ -class ITensor; - -/** Interface for an element-wise unary operation kernel - * - * Element-wise operation is computed by: - * @f[ output(x) = OP(input(x))@f] - * - */ -class NEElementwiseUnaryKernel : public INEKernel -{ -public: - const char *name() const override - { - return "NEElementwiseUnaryKernel"; - } - /** Default constructor */ - NEElementwiseUnaryKernel(); - /** Prevent instances of this class from being copied (As this class contains pointers) */ - NEElementwiseUnaryKernel(const NEElementwiseUnaryKernel &) = delete; - /** Prevent instances of this class from being copied (As this class contains pointers) */ - NEElementwiseUnaryKernel &operator=(const NEElementwiseUnaryKernel &) = delete; - /** Allow instances of this class to be moved */ - NEElementwiseUnaryKernel(NEElementwiseUnaryKernel &&) = default; - /** Allow instances of this class to be moved */ - NEElementwiseUnaryKernel &operator=(NEElementwiseUnaryKernel &&) = default; - /** Default destructor */ - ~NEElementwiseUnaryKernel() = default; - - /** Function to configure the @ref NEElementwiseUnaryKernel - * - * @param[in] op Arithmetic operation to be executed. - * @param[in] input First tensor input. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. - * @param[out] output Output tensor. Data types supported: Same as @p input. - */ - void configure(ElementWiseUnary op, const ITensor *input, ITensor *output); - - /** Static function to check if given info will lead to a valid configuration of @ref NEElementwiseUnaryKernel - * - * @param[in] op Arithmetic operation to be executed. - * @param[in] input First tensor input info. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. - * @param[in] output Output tensor info. Data types supported: Same as @p input. - * - * @return a Status - */ - static Status validate(ElementWiseUnary op, const ITensorInfo *input, const ITensorInfo *output); - - // Inherited methods overridden: - void run(const Window &window, const ThreadInfo &info) override; - - /** Common signature for all the specialised elementwise unary micro-kernels - * - * @param[in] window Region on which to execute the kernel. - */ - using ElementwiseUnaryUkernelPtr = std::add_pointer::type; - -private: - ElementwiseUnaryUkernelPtr _func; - const ITensor *_input; - ITensor *_output; - ElementWiseUnary _op; -}; -} // namespace arm_compute -#endif /* ARM_COMPUTE_NEELEMENTWISEUNARYKERNEL_H */ diff --git a/src/core/NEON/kernels/elementwise/impl/elementwise_unary_list.h b/src/core/NEON/kernels/elementwise/impl/elementwise_unary_list.h deleted file mode 100644 index 307e95fae9..0000000000 --- a/src/core/NEON/kernels/elementwise/impl/elementwise_unary_list.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H -#define SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H - -#include "arm_compute/core/Types.h" -#include "src/core/NEON/wrapper/intrinsics/intrinsics.h" - -namespace arm_compute -{ -namespace cpu -{ -template -inline ScalarType elementwise_op_scalar_imp(ElementWiseUnary op, const ScalarType &a) -{ - switch(op) - { - case ElementWiseUnary::RSQRT: - return 1 / sqrt(a); - case ElementWiseUnary::EXP: - return std::exp(a); - case ElementWiseUnary::NEG: - return -a; - case ElementWiseUnary::LOG: - return std::log(a); - case ElementWiseUnary::ABS: - return std::abs(a); - case ElementWiseUnary::ROUND: - return support::cpp11::nearbyint(a); - case ElementWiseUnary::SIN: - return std::sin(a); - default: - ARM_COMPUTE_ERROR("NOT_SUPPORTED!"); - } -} - -template -inline VectorType elementwise_op_imp(ElementWiseUnary op, const VectorType &a) -{ - switch(op) - { - case ElementWiseUnary::RSQRT: - return wrapper::vinvsqrt(a); - case ElementWiseUnary::EXP: - return wrapper::vexpq(a); - case ElementWiseUnary::NEG: - return wrapper::vneg(a); - case ElementWiseUnary::LOG: - return wrapper::vlog(a); - case ElementWiseUnary::ABS: - return wrapper::vabs(a); - case ElementWiseUnary::ROUND: - return wrapper::vround(a); - case ElementWiseUnary::SIN: - return wrapper::vsin(a); - default: - ARM_COMPUTE_ERROR("NOT_SUPPORTED!"); - } -} - -template -void elementwise_op(const ITensor *in, ITensor *out, const Window &window, ElementWiseUnary op) -{ - const int window_step_x = 16 / sizeof(ScalarType); - const auto window_start_x = static_cast(window.x().start()); - const auto window_end_x = static_cast(window.x().end()); - - Window win = window; - win.set(Window::DimX, Window::Dimension(0, 1, 1)); - - Iterator input(in, win); - Iterator output(out, win); - - execute_window_loop(win, [&](const Coordinates &) - { - auto output_ptr = reinterpret_cast(output.ptr()); - const auto input_ptr = reinterpret_cast(input.ptr()); - - int x = window_start_x; - for(; x <= window_end_x - window_step_x; x += window_step_x) - { - wrapper::vstore(output_ptr + x, elementwise_op_imp(op, wrapper::vloadq(input_ptr + x))); - } - for(; x < window_end_x; ++x) - { - *(output_ptr + x) = elementwise_op_scalar_imp(op, *(input_ptr + x)); - } - }, - input, output); -} - -} // namespace cpu -} // namespace arm_compute - -#endif // SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H \ No newline at end of file diff --git a/src/core/SVE/kernels/elementwise/impl/elementwise_unary_list.h b/src/core/SVE/kernels/elementwise/impl/elementwise_unary_list.h deleted file mode 100644 index 23502c71e5..0000000000 --- a/src/core/SVE/kernels/elementwise/impl/elementwise_unary_list.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef SRC_CORE_SVE_KERNELS_ELEMENTWISE_UNARY_LIST_H -#define SRC_CORE_SVE_KERNELS_ELEMENTWISE_UNARY_LIST_H - -#include "arm_compute/core/Types.h" -#include "arm_compute/core/utils/misc/Traits.h" -#include "src/core/NEON/wrapper/intrinsics/intrinsics.h" -#if defined(__ARM_FEATURE_SVE) -#include "src/core/NEON/SVEMath.h" -#include - -namespace arm_compute -{ -namespace cpu -{ -template -inline typename std::enable_if::value, VectorType>::type elementwise_op_sve_imp(svbool_t pg, ElementWiseUnary op, const VectorType &a) -{ - switch(op) - { - case ElementWiseUnary::RSQRT: - return svinvsqrt(pg, a); - case ElementWiseUnary::EXP: - return wrapper::svexp_z(pg, a); - case ElementWiseUnary::NEG: - return svneg_z(pg, a); - case ElementWiseUnary::LOG: - return wrapper::svlog_z(pg, a); - case ElementWiseUnary::ABS: - return svabs_z(pg, a); - case ElementWiseUnary::ROUND: - return svrintn_z(pg, a); - case ElementWiseUnary::SIN: - return wrapper::svsin_z(pg, a); - default: - ARM_COMPUTE_ERROR("NOT_SUPPORTED"); - } -} - -template -inline typename std::enable_if::value, VectorType>::type elementwise_op_sve_imp(svbool_t pg, ElementWiseUnary op, const VectorType &a) -{ - switch(op) - { - case ElementWiseUnary::NEG: - return svneg_z(pg, a); - case ElementWiseUnary::ABS: - return svabs_z(pg, a); - default: - ARM_COMPUTE_ERROR("NOT_SUPPORTED"); - } -} - -template -void elementwise_sve_op(const ITensor *in, ITensor *out, const Window &window, ElementWiseUnary op) -{ - const auto all_true_pg = wrapper::svptrue(); - const auto window_start_x = static_cast(window.x().start()); - const auto window_end_x = static_cast(window.x().end()); - - Window win = window; - win.set(Window::DimX, Window::Dimension(0, 1, 1)); - - Iterator input(in, win); - Iterator output(out, win); - - execute_window_loop(win, [&](const Coordinates &) - { - auto output_ptr = reinterpret_cast(output.ptr()); - const auto input_ptr = reinterpret_cast(input.ptr()); - int x = window_start_x; - - svbool_t pg = wrapper::svwhilelt(x, window_end_x); - do - { - const auto vin = svld1(pg, input_ptr + x); - svst1(pg, output_ptr + x, elementwise_op_sve_imp(pg, op, vin)); - x += wrapper::svcnt(); - pg = wrapper::svwhilelt(x, window_end_x); - } - while(svptest_any(all_true_pg, pg)); - }, - input, output); -} - -} // namespace cpu -} // namespace arm_compute -#endif // defined(__ARM_FEATURE_SVE) -#endif // SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H \ No newline at end of file diff --git a/src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp b/src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp new file mode 100644 index 0000000000..d2681bb060 --- /dev/null +++ b/src/core/cpu/kernels/CpuElementwiseUnaryKernel.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018-2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/core/cpu/kernels/CpuElementwiseUnaryKernel.h" + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/ITensor.h" +#include "arm_compute/core/Validate.h" +#include "src/core/CPP/Validate.h" +#include "src/core/common/Registrars.h" +#include "src/core/cpu/kernels/elementwise/neon/elementwise_unary_list.h" +#include "src/core/cpu/kernels/elementwise/sve/elementwise_unary_list.h" +#include "src/core/helpers/AutoConfiguration.h" +#include "src/core/helpers/WindowHelpers.h" +#include "support/ToolchainSupport.h" + +namespace arm_compute +{ +namespace cpu +{ +namespace kernels +{ +namespace +{ +using ElementwiseUnarySelector = std::add_pointer::type; + +struct ElementwiseUnaryKernel +{ + const char *name; + const ElementwiseUnarySelector is_selected; + CpuElementwiseUnaryKernel::ElementwiseUnaryUkernelPtr ukernel; +}; + +static const ElementwiseUnaryKernel available_kernels[] = +{ +#if defined(__ARM_FEATURE_SVE) + { + "fp32_sve_elementwise_unary", + [](DataType dt) { return dt == DataType::F32; }, + REGISTER_FP32_SVE(arm_compute::cpu::elementwise_sve_op), + }, + { + "fp16_sve_elementwise_unary", + [](DataType dt) { return dt == DataType::F16; }, + REGISTER_FP16_SVE(arm_compute::cpu::elementwise_sve_op<__fp16>), + }, + { + "s32_sve_elementwise_unary", + [](DataType dt) { return dt == DataType::S32; }, + REGISTER_INTEGER_SVE(arm_compute::cpu::elementwise_sve_op), + }, +#endif // defined(__ARM_FEATURE_SVE) + { + "fp32_neon_elementwise_unary", + [](DataType dt) { return dt == DataType::F32; }, + REGISTER_FP32_NEON(arm_compute::cpu::elementwise_op), + }, +#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) + { + "fp16_neon_elementwise_unary", + [](DataType dt) { return dt == DataType::F16; }, + REGISTER_FP32_NEON(arm_compute::cpu::elementwise_op<__fp16>), + }, +#endif // defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) + { + "s32_neon_elementwise_unary", + [](DataType dt) { return dt == DataType::S32; }, + REGISTER_INTEGER_NEON(arm_compute::cpu::elementwise_op), + }, +}; + +const ElementwiseUnaryKernel *get_implementation(DataType dt) +{ + for(const auto &uk : available_kernels) + { + if(uk.is_selected(dt)) + { + return &uk; + } + } + return nullptr; +} +} // namespace + +CpuElementwiseUnaryKernel::CpuElementwiseUnaryKernel() + : _op() +{ +} + +void CpuElementwiseUnaryKernel::configure(ElementWiseUnary op, const ITensorInfo &input, ITensorInfo &output) +{ + ARM_COMPUTE_ERROR_THROW_ON(validate(op, input, output)); + + // Configure kernel window + const std::pair broadcast_pair = ITensorInfo::broadcast_shape_and_valid_region(input); + const TensorShape &out_shape = broadcast_pair.first; + const ValidRegion &valid_region = broadcast_pair.second; + + // Auto initialize output if not initialized + auto_init_if_empty(output, out_shape, 1, input.data_type()); + + Window win = calculate_max_window(valid_region); + + _op = op; + + ICpuKernel::configure(win); +} + +Status CpuElementwiseUnaryKernel::validate(ElementWiseUnary op, const ITensorInfo &input, const ITensorInfo &output) +{ + ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(&input); + + const auto *uk = get_implementation(input.data_type()); + ARM_COMPUTE_RETURN_ERROR_ON(uk == nullptr || uk->ukernel == nullptr); + + switch(op) + { + case ElementWiseUnary::EXP: + case ElementWiseUnary::RSQRT: + case ElementWiseUnary::LOG: + case ElementWiseUnary::ROUND: + case ElementWiseUnary::SIN: + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(&input, 1, DataType::F16, DataType::F32); + break; + case ElementWiseUnary::NEG: + case ElementWiseUnary::ABS: + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(&input, 1, DataType::F16, DataType::F32, DataType::S32); + break; + default: + ARM_COMPUTE_ERROR("ElementWiseUnary operation not supported"); + } + // Validate in case of configured output + if(output.total_size() > 0) + { + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(&input, &output); + } + + return Status{}; +} + +void CpuElementwiseUnaryKernel::run_op(ITensorPack &tensors, const Window &window, const ThreadInfo &info) +{ + ARM_COMPUTE_UNUSED(info); + ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this); + ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(ICpuKernel::window(), window); + + auto src = tensors.get_const_tensor(TensorType::ACL_SRC); + auto dst = tensors.get_tensor(TensorType::ACL_DST); + auto func = get_implementation(src->info()->data_type())->ukernel; + ARM_COMPUTE_ERROR_ON(func == nullptr); + func(src, dst, window, _op); +} +} // namespace kernels +} // namespace cpu +} // namespace arm_compute diff --git a/src/core/cpu/kernels/CpuElementwiseUnaryKernel.h b/src/core/cpu/kernels/CpuElementwiseUnaryKernel.h new file mode 100644 index 0000000000..193f6f1e4f --- /dev/null +++ b/src/core/cpu/kernels/CpuElementwiseUnaryKernel.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_KERNEL_H +#define ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_KERNEL_H + +#include "arm_compute/core/Types.h" +#include "src/core/common/Macros.h" +#include "src/core/cpu/ICpuKernel.h" + +namespace arm_compute +{ +class ITensor; +namespace cpu +{ +namespace kernels +{ +/** Interface for an element-wise unary operation kernel + * + * Element-wise operation is computed by: + * @f[ output(x) = OP(input(x))@f] + * + */ +class CpuElementwiseUnaryKernel : public ICpuKernel +{ +public: + const char *name() const override + { + return "CpuElementwiseUnaryKernel"; + } + /** Default constructor */ + CpuElementwiseUnaryKernel(); + /** Default destructor */ + ~CpuElementwiseUnaryKernel() = default; + ARM_COMPUTE_DISALLOW_COPY_ALLOW_MOVE(CpuElementwiseUnaryKernel); + + /** Function to configure the @ref CpuElementwiseUnaryKernel + * + * @param[in] op Arithmetic operation to be executed. + * @param[in] input First tensor input. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. + * @param[out] output Output tensor. Data types supported: Same as @p input. + */ + void configure(ElementWiseUnary op, const ITensorInfo &input, ITensorInfo &output); + + /** Static function to check if given info will lead to a valid configuration of @ref CpuElementwiseUnaryKernel + * + * @param[in] op Arithmetic operation to be executed. + * @param[in] input First tensor input info. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. + * @param[in] output Output tensor info. Data types supported: Same as @p input. + * + * @return a Status + */ + static Status validate(ElementWiseUnary op, const ITensorInfo &input, const ITensorInfo &output); + + // Inherited methods overridden: + void run_op(ITensorPack &tensors, const Window &window, const ThreadInfo &info) override; + + /** Common signature for all the specialised elementwise unary micro-kernels + * + * @param[in] window Region on which to execute the kernel. + */ + using ElementwiseUnaryUkernelPtr = std::add_pointer::type; + +private: + ElementWiseUnary _op; +}; +} // namespace kernels +} // namespace cpu +} // namespace arm_compute +#endif /* ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_KERNEL_H */ diff --git a/src/core/cpu/kernels/elementwise/neon/elementwise_unary_list.h b/src/core/cpu/kernels/elementwise/neon/elementwise_unary_list.h new file mode 100644 index 0000000000..307e95fae9 --- /dev/null +++ b/src/core/cpu/kernels/elementwise/neon/elementwise_unary_list.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H +#define SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H + +#include "arm_compute/core/Types.h" +#include "src/core/NEON/wrapper/intrinsics/intrinsics.h" + +namespace arm_compute +{ +namespace cpu +{ +template +inline ScalarType elementwise_op_scalar_imp(ElementWiseUnary op, const ScalarType &a) +{ + switch(op) + { + case ElementWiseUnary::RSQRT: + return 1 / sqrt(a); + case ElementWiseUnary::EXP: + return std::exp(a); + case ElementWiseUnary::NEG: + return -a; + case ElementWiseUnary::LOG: + return std::log(a); + case ElementWiseUnary::ABS: + return std::abs(a); + case ElementWiseUnary::ROUND: + return support::cpp11::nearbyint(a); + case ElementWiseUnary::SIN: + return std::sin(a); + default: + ARM_COMPUTE_ERROR("NOT_SUPPORTED!"); + } +} + +template +inline VectorType elementwise_op_imp(ElementWiseUnary op, const VectorType &a) +{ + switch(op) + { + case ElementWiseUnary::RSQRT: + return wrapper::vinvsqrt(a); + case ElementWiseUnary::EXP: + return wrapper::vexpq(a); + case ElementWiseUnary::NEG: + return wrapper::vneg(a); + case ElementWiseUnary::LOG: + return wrapper::vlog(a); + case ElementWiseUnary::ABS: + return wrapper::vabs(a); + case ElementWiseUnary::ROUND: + return wrapper::vround(a); + case ElementWiseUnary::SIN: + return wrapper::vsin(a); + default: + ARM_COMPUTE_ERROR("NOT_SUPPORTED!"); + } +} + +template +void elementwise_op(const ITensor *in, ITensor *out, const Window &window, ElementWiseUnary op) +{ + const int window_step_x = 16 / sizeof(ScalarType); + const auto window_start_x = static_cast(window.x().start()); + const auto window_end_x = static_cast(window.x().end()); + + Window win = window; + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + + Iterator input(in, win); + Iterator output(out, win); + + execute_window_loop(win, [&](const Coordinates &) + { + auto output_ptr = reinterpret_cast(output.ptr()); + const auto input_ptr = reinterpret_cast(input.ptr()); + + int x = window_start_x; + for(; x <= window_end_x - window_step_x; x += window_step_x) + { + wrapper::vstore(output_ptr + x, elementwise_op_imp(op, wrapper::vloadq(input_ptr + x))); + } + for(; x < window_end_x; ++x) + { + *(output_ptr + x) = elementwise_op_scalar_imp(op, *(input_ptr + x)); + } + }, + input, output); +} + +} // namespace cpu +} // namespace arm_compute + +#endif // SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H \ No newline at end of file diff --git a/src/core/cpu/kernels/elementwise/sve/elementwise_unary_list.h b/src/core/cpu/kernels/elementwise/sve/elementwise_unary_list.h new file mode 100644 index 0000000000..23502c71e5 --- /dev/null +++ b/src/core/cpu/kernels/elementwise/sve/elementwise_unary_list.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_CORE_SVE_KERNELS_ELEMENTWISE_UNARY_LIST_H +#define SRC_CORE_SVE_KERNELS_ELEMENTWISE_UNARY_LIST_H + +#include "arm_compute/core/Types.h" +#include "arm_compute/core/utils/misc/Traits.h" +#include "src/core/NEON/wrapper/intrinsics/intrinsics.h" +#if defined(__ARM_FEATURE_SVE) +#include "src/core/NEON/SVEMath.h" +#include + +namespace arm_compute +{ +namespace cpu +{ +template +inline typename std::enable_if::value, VectorType>::type elementwise_op_sve_imp(svbool_t pg, ElementWiseUnary op, const VectorType &a) +{ + switch(op) + { + case ElementWiseUnary::RSQRT: + return svinvsqrt(pg, a); + case ElementWiseUnary::EXP: + return wrapper::svexp_z(pg, a); + case ElementWiseUnary::NEG: + return svneg_z(pg, a); + case ElementWiseUnary::LOG: + return wrapper::svlog_z(pg, a); + case ElementWiseUnary::ABS: + return svabs_z(pg, a); + case ElementWiseUnary::ROUND: + return svrintn_z(pg, a); + case ElementWiseUnary::SIN: + return wrapper::svsin_z(pg, a); + default: + ARM_COMPUTE_ERROR("NOT_SUPPORTED"); + } +} + +template +inline typename std::enable_if::value, VectorType>::type elementwise_op_sve_imp(svbool_t pg, ElementWiseUnary op, const VectorType &a) +{ + switch(op) + { + case ElementWiseUnary::NEG: + return svneg_z(pg, a); + case ElementWiseUnary::ABS: + return svabs_z(pg, a); + default: + ARM_COMPUTE_ERROR("NOT_SUPPORTED"); + } +} + +template +void elementwise_sve_op(const ITensor *in, ITensor *out, const Window &window, ElementWiseUnary op) +{ + const auto all_true_pg = wrapper::svptrue(); + const auto window_start_x = static_cast(window.x().start()); + const auto window_end_x = static_cast(window.x().end()); + + Window win = window; + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + + Iterator input(in, win); + Iterator output(out, win); + + execute_window_loop(win, [&](const Coordinates &) + { + auto output_ptr = reinterpret_cast(output.ptr()); + const auto input_ptr = reinterpret_cast(input.ptr()); + int x = window_start_x; + + svbool_t pg = wrapper::svwhilelt(x, window_end_x); + do + { + const auto vin = svld1(pg, input_ptr + x); + svst1(pg, output_ptr + x, elementwise_op_sve_imp(pg, op, vin)); + x += wrapper::svcnt(); + pg = wrapper::svwhilelt(x, window_end_x); + } + while(svptest_any(all_true_pg, pg)); + }, + input, output); +} + +} // namespace cpu +} // namespace arm_compute +#endif // defined(__ARM_FEATURE_SVE) +#endif // SRC_CORE_NEON_KERNELS_ELEMENTWISE_UNARY_LIST_H \ No newline at end of file diff --git a/src/runtime/NEON/functions/NEElementwiseUnaryLayer.cpp b/src/runtime/NEON/functions/NEElementwiseUnaryLayer.cpp index 5c779f1489..1a9e8839ca 100644 --- a/src/runtime/NEON/functions/NEElementwiseUnaryLayer.cpp +++ b/src/runtime/NEON/functions/NEElementwiseUnaryLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 Arm Limited. + * Copyright (c) 2018-2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -22,88 +22,63 @@ * SOFTWARE. */ #include "arm_compute/runtime/NEON/functions/NEElementwiseUnaryLayer.h" - -#include "src/core/NEON/kernels/NEElementwiseUnaryKernel.h" - +#include "src/runtime/cpu/operators/CpuElementwiseUnary.h" #include namespace arm_compute { -void NERsqrtLayer::configure(const ITensor *input, ITensor *output) -{ - auto k = std::make_unique(); - k->configure(ElementWiseUnary::RSQRT, input, output); - _kernel = std::move(k); -} -Status NERsqrtLayer::validate(const ITensorInfo *input, const ITensorInfo *output) -{ - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::RSQRT, input, output); -} +using OperatorType = cpu::CpuElementwiseUnary; -void NEExpLayer::configure(const ITensor *input, ITensor *output) +template +struct NEElementwiseUnaryLayer::Impl { - auto k = std::make_unique(); - k->configure(ElementWiseUnary::EXP, input, output); - _kernel = std::move(k); -} -Status NEExpLayer::validate(const ITensorInfo *input, const ITensorInfo *output) -{ - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::EXP, input, output); -} + const ITensor *src{ nullptr }; + ITensor *dst{ nullptr }; + std::unique_ptr cpu_op{ nullptr }; +}; -void NENegLayer::configure(const ITensor *input, ITensor *output) -{ - auto k = std::make_unique(); - k->configure(ElementWiseUnary::NEG, input, output); - _kernel = std::move(k); -} -Status NENegLayer::validate(const ITensorInfo *input, const ITensorInfo *output) +template +NEElementwiseUnaryLayer::NEElementwiseUnaryLayer() + : _impl(std::make_unique()) { - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::NEG, input, output); } +template +NEElementwiseUnaryLayer::~NEElementwiseUnaryLayer() = default; +template +NEElementwiseUnaryLayer::NEElementwiseUnaryLayer(NEElementwiseUnaryLayer &&) = default; +template +NEElementwiseUnaryLayer &NEElementwiseUnaryLayer::operator=(NEElementwiseUnaryLayer &&) = default; -void NELogLayer::configure(const ITensor *input, ITensor *output) +template +void NEElementwiseUnaryLayer::configure(const ITensor *input, ITensor *output) { - auto k = std::make_unique(); - k->configure(ElementWiseUnary::LOG, input, output); - _kernel = std::move(k); -} -Status NELogLayer::validate(const ITensorInfo *input, const ITensorInfo *output) -{ - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::LOG, input, output); + _impl->src = input; + _impl->dst = output; + _impl->cpu_op = std::make_unique(); + _impl->cpu_op->configure(op, *_impl->src->info(), *_impl->dst->info()); } -void NEAbsLayer::configure(const ITensor *input, ITensor *output) +template +Status NEElementwiseUnaryLayer::validate(const ITensorInfo *input, const ITensorInfo *output) { - auto k = std::make_unique(); - k->configure(ElementWiseUnary::ABS, input, output); - _kernel = std::move(k); -} -Status NEAbsLayer::validate(const ITensorInfo *input, const ITensorInfo *output) -{ - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::ABS, input, output); + return OperatorType::validate(op, *input, *output); } -void NERoundLayer::configure(const ITensor *input, ITensor *output) -{ - auto k = std::make_unique(); - k->configure(ElementWiseUnary::ROUND, input, output); - _kernel = std::move(k); -} -Status NERoundLayer::validate(const ITensorInfo *input, const ITensorInfo *output) +template +void NEElementwiseUnaryLayer::run() { - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::ROUND, input, output); + ITensorPack pack; + pack.add_tensor(TensorType::ACL_SRC, _impl->src); + pack.add_tensor(TensorType::ACL_DST, _impl->dst); + _impl->cpu_op->run(pack); } -void NESinLayer::configure(const ITensor *input, ITensor *output) -{ - auto k = std::make_unique(); - k->configure(ElementWiseUnary::SIN, input, output); - _kernel = std::move(k); -} -Status NESinLayer::validate(const ITensorInfo *input, const ITensorInfo *output) -{ - return NEElementwiseUnaryKernel::validate(ElementWiseUnary::SIN, input, output); -} +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; +template class NEElementwiseUnaryLayer; } // namespace arm_compute diff --git a/src/runtime/cpu/operators/CpuElementwiseUnary.cpp b/src/runtime/cpu/operators/CpuElementwiseUnary.cpp new file mode 100644 index 0000000000..d1b1700927 --- /dev/null +++ b/src/runtime/cpu/operators/CpuElementwiseUnary.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/runtime/cpu/operators/CpuElementwiseUnary.h" +#include "src/core/cpu/kernels/CpuElementwiseUnaryKernel.h" + +namespace arm_compute +{ +namespace cpu +{ +using KernelType = kernels::CpuElementwiseUnaryKernel; + +void CpuElementwiseUnary::configure(ElementWiseUnary op, const ITensorInfo &src, ITensorInfo &dst) +{ + auto k = std::make_unique(); + k->configure(op, src, dst); + _kernel = std::move(k); +} + +Status CpuElementwiseUnary::validate(ElementWiseUnary op, const ITensorInfo &src, const ITensorInfo &dst) +{ + return KernelType::validate(op, src, dst); +} +} // namespace cpu +} // namespace arm_compute \ No newline at end of file diff --git a/src/runtime/cpu/operators/CpuElementwiseUnary.h b/src/runtime/cpu/operators/CpuElementwiseUnary.h new file mode 100644 index 0000000000..0b2a9e730d --- /dev/null +++ b/src/runtime/cpu/operators/CpuElementwiseUnary.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_H +#define ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_H + +#include "arm_compute/core/Types.h" +#include "src/runtime/cpu/ICpuOperator.h" + +namespace arm_compute +{ +namespace cpu +{ +class CpuElementwiseUnary : public ICpuOperator +{ +public: + /** Initialize the function + * + * @param[in] op Unary operation to execute + * @param[in] src Input tensor information. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. + * @param[out] dst Output tensor information. Data types supported: Same as @p src. + */ + void configure(ElementWiseUnary op, const ITensorInfo &src, ITensorInfo &dst); + /** Static function to check if given info will lead to a valid configuration + * + * @param[in] op Unary operation to execute + * @param[in] src First tensor input info. Data types supported: F16/F32, F16/F32/S32 for NEG/ABS operations. + * @param[in] dst Output tensor info. Data types supported: Same as @p input. + * + * @return a status + */ + static Status validate(ElementWiseUnary op, const ITensorInfo &src, const ITensorInfo &dst); +}; + +} // namespace cpu +} // namespace arm_compute + +#endif /* ARM_COMPUTE_CPU_ELEMENTWISE_UNARY_H */ \ No newline at end of file -- cgit v1.2.1