text: ﻿/*
  // Copyright (c) 2016 Intel Corporation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  */
  
  #include "eltwise_kernel_vload8.h"
  #include "kernel_selector_utils.h" 
  
  namespace kernel_selector {
  
      ParamsKey EltwiseKernel_vload8::GetSupportedKey() const
      {
          ParamsKey k;
          k.EnableInputDataType(Datatype::F16);
          k.EnableInputDataType(Datatype::F32);
          k.EnableOutputDataType(Datatype::F16);
          k.EnableOutputDataType(Datatype::F32);
          k.EnableAllInputLayout();
          k.EnableAllOutputLayout();
          k.EnableBatching();
          return k;
      }
  
      JitConstants EltwiseKernel_vload8::GetJitConstants(const eltwise_params& params) const
      {
          return GetJitConstantsCommon(params, true);
      }
  
      bool EltwiseKernel_vload8::Validate(const Params& params, const optional_params& o) const
      {
          if (!EltwiseKernelBase::Validate(params, o))
          {
              return false;
          }
  
          const auto& ewParams = static_cast<const eltwise_params&>(params);
          const auto& output = ewParams.output;
          const auto count = output.PhysicalSize();
  
          const bool bSupportedCount = (count % 8) == 0;
          
          bool bCheckSizes = true;
          for (size_t i = 0; i < ewParams.inputs.size(); i++)
          {
              //allow only the same input sizes or scalars, without pitches
              if (ewParams.inputs[i].PitchesDifferFromLogicalDims() ||
                 (!(ewParams.inputs[0] == ewParams.inputs[i] && ewParams.inputs[i] == ewParams.output) &&
                     ewParams.inputs[i].PhysicalSize() != 1))
                  bCheckSizes = false;
          }
  
          //TODO: add support to this implementation when user requests input values updates
          bool bCheckUpdateInput = true;
          if (!ewParams.eltwiseParams.updateInputIds.empty())
              bCheckUpdateInput = false;
  
          //TODO: add support for reading from output buffer and using its values in computation
          bool bCheckUseOutput = true;
          for (size_t op = 0; op < ewParams.eltwiseParams.operations.size(); op++)
          {
              for (size_t input_idx = 0; input_idx < ewParams.eltwiseParams.operations[op].inputs.size(); input_idx++)
              {
                  if (ewParams.eltwiseParams.operations[op].inputs[input_idx].mode == EltwiseInputMode::OUTPUT_BUFFER)
                  {
                      bCheckUseOutput = false;
                      break;
                  }
              }
          }
  
          if (!bCheckSizes || !bSupportedCount || !bCheckUpdateInput || !bCheckUseOutput)
          {
              return false;
          }
  
          return true;
      }
  
      KernelsData EltwiseKernel_vload8::GetKernelsData(const Params& params, const optional_params& options) const
      {
          if (!Validate(params, options))
          {
              return{};
          }
  
          KernelData kd = KernelData::Default<eltwise_params>(params);
          eltwise_params& newParams = *static_cast<eltwise_params*>(kd.params.get());
  
          std::string jit;
  
          auto entry_point = GetEntryPoint(kernelName, newParams.layerID, options);
  
          try
          {
              auto cldnn_jit = GetJitConstants(newParams);
              jit = CreateJit(kernelName, cldnn_jit, entry_point);
          }
          catch (const std::runtime_error&)
          {
              return KernelsData();
          }
  
          auto& kernel = kd.kernels[0];
          kernel.workGroups.global = { std::max(newParams.inputs[0].LogicalSize()/8, (size_t)1), 1, 1 };
          kernel.workGroups.local = GetOptimalLocalWorkGroupSizes(kernel.workGroups.global);
          kernel.kernelString = GetKernelString(kernelName, jit, entry_point, ROUND_ROBIN);
          kernel.arguments = GetArgsDesc((uint32_t)newParams.inputs.size(), false, false);
  
          kd.estimatedTime = FORCE_PRIORITY_8;
  
          return{ kd };
      }
  }