void Transpose(const TransposeParams& unshrinked_params,
               const RuntimeShape& unshrinked_input_shape, const T* input_data,
               const RuntimeShape& unshrinked_output_shape, T* output_data) {
  ruy::profiler::ScopeLabel label("Transpose");

  const int output_size = unshrinked_output_shape.DimensionsCount();
  TFLITE_DCHECK_LE(unshrinked_input_shape.DimensionsCount(), N);
  TFLITE_DCHECK_LE(output_size, N);
  TFLITE_DCHECK_EQ(output_size, unshrinked_params.perm_count);

  RuntimeShape shrinked_input_shape = RuntimeShape(unshrinked_input_shape);
  RuntimeShape shrinked_output_shape = RuntimeShape(unshrinked_output_shape);
  TransposeParams shrinked_params = unshrinked_params;

  // Reduce any dimensions that have one size. Lower transpose op usually
  // performs better since memory access patterns will be improved.
  transpose_utils::RemoveOneSizeDimensions(
      &shrinked_input_shape, &shrinked_output_shape, &shrinked_params);

  // Handle identity cases.
  // TODO(b/140779653): Add an optimization pass in the conversion process to
  // remove transpose op nodes where they do nothing like the below one.
  bool identical = true;
  for (int i = 0; i < shrinked_params.perm_count; ++i) {
    if (shrinked_params.perm[i] != i) {
      identical = false;
      break;
    }
  }
  if (identical) {
    memcpy(output_data, input_data,
           unshrinked_input_shape.FlatSize() * sizeof(T));
    return;
  }

  // Reduce dimensions by flattening.
  if (shrinked_params.perm[0] == 0 && output_size >= 3) {
    RuntimeShape non_flatten_input_shape;
    RuntimeShape non_flatten_output_shape;
    TransposeParams non_flatten_params;
    const int total_size = shrinked_input_shape.FlatSize();
    const int non_flatten_size = transpose_utils::Flatten(
        shrinked_input_shape, shrinked_output_shape, shrinked_params,
        &non_flatten_input_shape, &non_flatten_output_shape,
        &non_flatten_params);
    TFLITE_DCHECK_NE(non_flatten_params.perm[0], 0);

    for (int i = 0; i < total_size; i += non_flatten_size) {
      TransposeImpl<T, N>(non_flatten_params, non_flatten_input_shape,
                          input_data + i, non_flatten_output_shape,
                          output_data + i);
    }
    return;
  }

  // Call non-flattened case.
  TransposeImpl<T, N>(shrinked_params, shrinked_input_shape, input_data,
                      shrinked_output_shape, output_data);
}
void Transpose(const TransposeParams& unshrinked_params,
               const RuntimeShape& unshrinked_input_shape, const T* input_data,
               const RuntimeShape& unshrinked_output_shape, T* output_data) {
  ruy::profiler::ScopeLabel label("Transpose");

  const int output_size = unshrinked_output_shape.DimensionsCount();
  TFLITE_DCHECK_LE(unshrinked_input_shape.DimensionsCount(), N);
  TFLITE_DCHECK_LE(output_size, N);
  TFLITE_DCHECK_EQ(output_size, unshrinked_params.perm_count);

  RuntimeShape shrinked_input_shape = RuntimeShape(unshrinked_input_shape);
  RuntimeShape shrinked_output_shape = RuntimeShape(unshrinked_output_shape);
  TransposeParams shrinked_params = unshrinked_params;

   
   
  transpose_utils::RemoveOneSizeDimensions(
      &shrinked_input_shape, &shrinked_output_shape, &shrinked_params);

   
   
   
  bool identical = true;
  for (int i = 0; i < shrinked_params.perm_count; ++i) {
    if (shrinked_params.perm[i] != i) {
      identical = false;
      break;
    }
  }
  if (identical) {
    memcpy(output_data, input_data,
           unshrinked_input_shape.FlatSize() * sizeof(T));
    return;
  }

   
  if (shrinked_params.perm[0] == 0 && output_size >= 3) {
    RuntimeShape non_flatten_input_shape;
    RuntimeShape non_flatten_output_shape;
    TransposeParams non_flatten_params;
    const int total_size = shrinked_input_shape.FlatSize();
    const int non_flatten_size = transpose_utils::Flatten(
        shrinked_input_shape, shrinked_output_shape, shrinked_params,
        &non_flatten_input_shape, &non_flatten_output_shape,
        &non_flatten_params);
    TFLITE_DCHECK_NE(non_flatten_params.perm[0], 0);

    for (int i = 0; i < total_size; i += non_flatten_size) {
      TransposeImpl<T, N>(non_flatten_params, non_flatten_input_shape,
                          input_data + i, non_flatten_output_shape,
                          output_data + i);
    }
    return;
  }

   
  TransposeImpl<T, N>(shrinked_params, shrinked_input_shape, input_data,
                      shrinked_output_shape, output_data);
}