text: /*
   * Copyright (c) 2018-2020 Ma Siyuan
   *
   * 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.
   */
  
  /* NOTE: this file is automatically generated by protos/op/dpu/ldmr.op
     using tools/addop.pl */
  
  #include <assert.h>
  #include "ln_op.h"
  #include "ln_arch.h"
  
  struct priv_s {
      ln_tensor_entry *src_entry;
      ln_tensor_entry *dst_entry;
  };
  
  /* This function should do the parameter checking and tensor shape inference. */
  static void ldmr_pre_run(ln_op_arg *op_arg)
  {
      char                 *src_name;
      ln_tensor_list_entry *src_list_entry;
      ln_tensor_entry      *src_entry;
      tl_tensor            *src;
      char                 *dst_name;
      ln_tensor_list_entry *dst_list_entry;
      ln_tensor_entry      *dst_entry;
      tl_tensor            *dst;
      int                   dst_ndim;
      int                  *dst_dims;
      tl_dtype              dst_dtype;
      int                   tensors_in_n;
      int                   tensors_out_n;
      int                   params_n;
      struct priv_s        *priv;
  
      /* check tensors and parameters */
      tensors_in_n = ln_tensor_list_length(op_arg->tensors_in);
      ln_opck_tensors_in_len_eq(tensors_in_n, 1);
  
      src_list_entry = ln_tensor_list_find_by_arg_name(op_arg->tensors_in, "src");
      ln_opck_tensor_in_exist(src_list_entry, "src");
      src_name = src_list_entry->name;
      src_entry = ln_tensor_table_find(op_arg->tensor_table, src_name);
      ln_opck_tensor_defined(src_entry, src_name);
      src = src_entry->tensor;
      src = src;
      ln_opck_tensor_ndim(src_entry, 2);
  
      tensors_out_n = ln_tensor_list_length(op_arg->tensors_out);
      ln_opck_tensors_out_len_eq(tensors_out_n, 1);
  
      dst_list_entry = ln_tensor_list_find_by_arg_name(op_arg->tensors_out, "dst");
      ln_opck_tensor_out_exist(dst_list_entry, "dst");
      dst_name = dst_list_entry->name;
      dst_entry = ln_tensor_table_find(op_arg->tensor_table, dst_name);
      ln_opck_tensor_not_defined(dst_entry, dst_name);
  
      params_n = ln_param_list_length(op_arg->params);
      ln_opck_params_len_eq(params_n, 0);
  
      /* define output tensor shape, tensor data should be NULL */
      dst_ndim = src->ndim;
      dst_dtype = src->dtype;
      /* begin custom code */
      {
      dst_dims = (int[]){src->dims[0], ln_next_multiple_power2(src->dims[1], 8)};
      }
      /* end custom code */
      dst = tl_tensor_create(NULL, dst_ndim, dst_dims, dst_dtype);
      dst_entry = ln_tensor_entry_create(dst_name, dst);
      dst_entry->offset = dst_list_entry->offset;
      ln_tensor_entry_set_creater(dst_entry, op_arg->name);
      dst_entry->mtype = LN_MEM_NONE;
      ln_tensor_table_insert(op_arg->tensor_table, dst_entry);
  
      /* use op_arg->priv to store private data to be used in other functions */
      priv = ln_alloc(sizeof(struct priv_s));
      priv->src_entry = src_entry;
      priv->dst_entry = dst_entry;
      op_arg->priv = priv;
  }
  
  /* This function should free all the memory allocated by other *_run()s. */
  static void ldmr_post_run(ln_op_arg *op_arg)
  {
      struct priv_s *priv = op_arg->priv;
  
      ln_tensor_table_remove(op_arg->tensor_table, priv->dst_entry->name);
      ln_free(priv);
  }
  
  static const char *in_arg_names[] = {
      "src",
      NULL
  };
  
  static const char *out_arg_names[] = {
      "dst",
      NULL
  };
  
  static const char *param_arg_names[] = {
      NULL
  };
  
  static const ln_param_type param_ptypes[] = {
  
  };
  
  /* specify other ln_op_arg fields */
  static ln_op_arg op_arg_ldmr = {
      .optype = "ldmr",
      .arch = "none",
      .in_arg_names = in_arg_names,
      .out_arg_names = out_arg_names,
      .param_arg_names = param_arg_names,
      .param_ptypes = param_ptypes,
  };
  
  /* struct used for op registration in ln_oplist.c */
  ln_op ln_opimpl_ldmr = {
      .op_arg = &op_arg_ldmr,
      .pre_run = ldmr_pre_run,
      .static_run = NULL,
      .run = NULL,
      .post_run = ldmr_post_run,
      .calc_offset = NULL,
  };
  