static void CopyOutputBackpropRegion(const DepthwiseArgs& args,
                                     const int64_t padded_filter_inner_dim_size,
                                     const int64_t in_r, const int64_t in_c,
                                     const T* out_backprop, T* buffer) {
  typedef typename Eigen::internal::packet_traits<T>::type Packet;
  static const int64_t kPacketSize = (sizeof(Packet) / sizeof(T));

  const int64_t stride = args.stride;
  const int64_t filter_rows = args.filter_rows;
  const int64_t filter_cols = args.filter_cols;
  const int64_t pad_rows = args.pad_rows;
  const int64_t pad_cols = args.pad_cols;
  const int64_t out_rows = args.out_rows;
  const int64_t out_cols = args.out_cols;

  // Calculate the output spatial region which used point (in_r, in_c) as input.
  const int64_t out_r_start =
      std::max(static_cast<int64_t>(0),
               (in_r - filter_rows + pad_rows + stride) / stride);
  const int64_t out_r_end = std::min(out_rows - 1, (in_r + pad_rows) / stride);
  const int64_t out_c_start =
      std::max(static_cast<int64_t>(0),
               (in_c - filter_cols + pad_cols + stride) / stride);
  const int64_t out_c_end = std::min(out_cols - 1, (in_c + pad_cols) / stride);

  // Zero-pad 'buffer' if output region is smaller than filter spatial size.
  const int64_t filter_spatial_size = args.filter_rows * args.filter_cols;
  if ((out_r_end - out_r_start + 1) < args.filter_rows ||
      (out_c_end - out_c_start + 1) < args.filter_cols) {
    memset(buffer, 0,
           filter_spatial_size * padded_filter_inner_dim_size * sizeof(T));
  }

  // Calculate vectorized and scalar (residual) lengths for 'in_depth'.
  const int64_t vectorized_size = (args.out_depth / kPacketSize) * kPacketSize;
  const int64_t scalar_size = args.out_depth % kPacketSize;
  const int64_t pad_size = scalar_size > 0 ? kPacketSize - scalar_size : 0;

  for (int out_r = out_r_start; out_r <= out_r_end; ++out_r) {
    const int64_t f_r = in_r + pad_rows - out_r * stride;
    for (int out_c = out_c_start; out_c <= out_c_end; ++out_c) {
      const int64_t f_c = in_c + pad_cols - out_c * stride;
      const int64_t buf_base =
          (f_r * filter_cols + f_c) * padded_filter_inner_dim_size;
      // Calculate index into 'out_backprop' for coordinate (out_r, out_c).
      auto* out_bprop =
          out_backprop + (out_r * args.out_cols + out_c) * args.out_depth;

      // Copy vectorized portion of inner dimension into 'buffer'.
      for (int64_t d = 0; d < vectorized_size; d += kPacketSize) {
        auto v = Eigen::internal::ploadu<Packet>(out_bprop + d);
        Eigen::internal::pstoreu<T>(buffer + buf_base + d, v);
      }
      // Copy scalar portion of out_bprop to 'buffer'
      for (int64_t d = 0; d < scalar_size; ++d) {
        buffer[buf_base + vectorized_size + d] = out_bprop[vectorized_size + d];
      }
      // Pad to vector-register width (if needed).
      for (int64_t d = 0; d < pad_size; ++d) {
        buffer[buf_base + vectorized_size + scalar_size + d] =
            static_cast<T>(0);
      }
    }
  }
}
static void CopyOutputBackpropRegion(const DepthwiseArgs& args,
                                     const int64_t padded_filter_inner_dim_size,
                                     const int64_t in_r, const int64_t in_c,
                                     const T* out_backprop, T* buffer) {
  typedef typename Eigen::internal::packet_traits<T>::type Packet;
  static const int64_t kPacketSize = (sizeof(Packet) / sizeof(T));

  const int64_t stride = args.stride;
  const int64_t filter_rows = args.filter_rows;
  const int64_t filter_cols = args.filter_cols;
  const int64_t pad_rows = args.pad_rows;
  const int64_t pad_cols = args.pad_cols;
  const int64_t out_rows = args.out_rows;
  const int64_t out_cols = args.out_cols;

   
  const int64_t out_r_start =
      std::max(static_cast<int64_t>(0),
               (in_r - filter_rows + pad_rows + stride) / stride);
  const int64_t out_r_end = std::min(out_rows - 1, (in_r + pad_rows) / stride);
  const int64_t out_c_start =
      std::max(static_cast<int64_t>(0),
               (in_c - filter_cols + pad_cols + stride) / stride);
  const int64_t out_c_end = std::min(out_cols - 1, (in_c + pad_cols) / stride);

   
  const int64_t filter_spatial_size = args.filter_rows * args.filter_cols;
  if ((out_r_end - out_r_start + 1) < args.filter_rows ||
      (out_c_end - out_c_start + 1) < args.filter_cols) {
    memset(buffer, 0,
           filter_spatial_size * padded_filter_inner_dim_size * sizeof(T));
  }

   
  const int64_t vectorized_size = (args.out_depth / kPacketSize) * kPacketSize;
  const int64_t scalar_size = args.out_depth % kPacketSize;
  const int64_t pad_size = scalar_size > 0 ? kPacketSize - scalar_size : 0;

  for (int out_r = out_r_start; out_r <= out_r_end; ++out_r) {
    const int64_t f_r = in_r + pad_rows - out_r * stride;
    for (int out_c = out_c_start; out_c <= out_c_end; ++out_c) {
      const int64_t f_c = in_c + pad_cols - out_c * stride;
      const int64_t buf_base =
          (f_r * filter_cols + f_c) * padded_filter_inner_dim_size;
       
      auto* out_bprop =
          out_backprop + (out_r * args.out_cols + out_c) * args.out_depth;

       
      for (int64_t d = 0; d < vectorized_size; d += kPacketSize) {
        auto v = Eigen::internal::ploadu<Packet>(out_bprop + d);
        Eigen::internal::pstoreu<T>(buffer + buf_base + d, v);
      }
       
      for (int64_t d = 0; d < scalar_size; ++d) {
        buffer[buf_base + vectorized_size + d] = out_bprop[vectorized_size + d];
      }
       
      for (int64_t d = 0; d < pad_size; ++d) {
        buffer[buf_base + vectorized_size + scalar_size + d] =
            static_cast<T>(0);
      }
    }
  }
}