/*
 * 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<bool(DataType)>::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<float>),
    },
    {
        "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<int32_t>),
    },
#endif // defined(__ARM_FEATURE_SVE)
    {
        "fp32_neon_elementwise_unary",
        [](DataType dt) { return dt == DataType::F32; },
        REGISTER_FP32_NEON(arm_compute::cpu::elementwise_op<float>),
    },
#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<int32_t>),
    },
};

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<TensorShape, ValidRegion> 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
