// File: dsharlet[P]array/test/image.cpp
// Function: void nda::test_copy<int, nda::shape<nda::dim<-9l, -9l, 1l>, nda::dim<-9l, -9l, -9l>, nda::dim<0l, 1l, 1l>>, nda::shape<nda::dim<-9l, -9l, 1l>, nda::dim<-9l, -9l, -9l>, nda::dim<0l, 1l, 1l>>>(long)
void test_copy(index_t channels) {
  array<T, ShapeSrc> src({40, 30, channels});
  fill_pattern(src);

  array<T, ShapeDest> dest({src.width(), src.height(), channels});
  copy(src, dest);
  check_pattern(dest);

  array<T, ShapeDest> dest_cropped({{5, 30}, {3, 20}, channels});
  copy(src, dest);
  check_pattern(dest);

  // If the src and dest shapes are the same, we should expect copies
  // to be about as fast as memcpy, even if the dest is cropped (so
  // some cleverness is required to copy rows at a time).
  // TODO: It would be nice if this were fast even for different shapes.
  // This may be impossible on x86. On ARM, using vstN/vldN, it may
  // be possible, but we need to find a way to sort dimensions by stride
  // while preserving the compile time constant extent.
#if 0
  if (std::is_same<ShapeSrc, ShapeDest>::value) {
    double copy_time = benchmark([&]() {
      copy(src, dest_cropped);
    });
    check_pattern(dest_cropped);

    array<T, ShapeDest> dest_memcpy(dest_cropped.shape());
    double memcpy_time = benchmark([&]() {
      std::memcpy(dest_memcpy.base(), src.base(), dest_cropped.size() * sizeof(T));
    });
    // This memcpy is *not* correct, but the performance of it
    // is optimistic.
    ASSERT(dest_memcpy != dest_cropped);

    ASSERT_LT(copy_time, memcpy_time * 1.2);
  }
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x260, %rsp            # imm = 0x260
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rcx
leaq -0x98(%rbp), %rdi
movq %rdi, -0x240(%rbp)
movl $0x28, %esi
movl $0x1e, %edx
callq 0x1160d0
movq -0x240(%rbp), %rsi
leaq -0x60(%rbp), %rdi
movq %rdi, -0x238(%rbp)
callq 0x10bde0
movq -0x238(%rbp), %rdi
xorl %esi, %esi
callq 0x116120
jmp 0x115a67
leaq -0x60(%rbp), %rdi
callq 0x116150
movq %rax, -0x248(%rbp)
jmp 0x115a79
leaq -0x60(%rbp), %rdi
callq 0x116170
movq %rax, -0x250(%rbp)
jmp 0x115a8b
movq -0x250(%rbp), %rdx
movq -0x248(%rbp), %rsi
movq -0x8(%rbp), %rcx
leaq -0x138(%rbp), %rdi
callq 0x116190
jmp 0x115aab
leaq -0x100(%rbp), %rdi
leaq -0x138(%rbp), %rsi
callq 0x10bde0
jmp 0x115ac0
leaq -0x60(%rbp), %rdi
leaq -0x100(%rbp), %rsi
callq 0x1161e0
jmp 0x115ad2
leaq -0x150(%rbp), %rdi
movq %rdi, -0x258(%rbp)
callq 0x35c10
movq -0x258(%rbp), %rsi
leaq -0x100(%rbp), %rdi
callq 0x116230
jmp 0x115afa
leaq -0x1f8(%rbp), %rdi
movl $0x5, %esi
movl $0x1e, %edx
movl $0x1, %ecx
callq 0x16d70
jmp 0x115b17
leaq -0x210(%rbp), %rdi
movl $0x3, %esi
movl $0x14, %edx
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
callq 0x10c60
jmp 0x115b39
movq -0x8(%rbp), %rsi
leaq -0x213(%rbp), %rdi
callq 0x116260
jmp 0x115b4b
leaq -0x1e0(%rbp), %rdi
leaq -0x1f8(%rbp), %rsi
leaq -0x210(%rbp), %rdx
leaq -0x213(%rbp), %rcx
callq 0x10bd80
jmp 0x115b6e
leaq -0x1a8(%rbp), %rdi
leaq -0x1e0(%rbp), %rsi
callq 0x10bde0
jmp 0x115b83
leaq -0x60(%rbp), %rdi
leaq -0x100(%rbp), %rsi
callq 0x1161e0
jmp 0x115b95
leaq -0x230(%rbp), %rdi
movq %rdi, -0x260(%rbp)
callq 0x35c10
movq -0x260(%rbp), %rsi
leaq -0x100(%rbp), %rdi
callq 0x116230
jmp 0x115bbd
leaq -0x1a8(%rbp), %rdi
callq 0x10bee0
leaq -0x100(%rbp), %rdi
callq 0x10bee0
leaq -0x60(%rbp), %rdi
callq 0x10bee0
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa0(%rbp)
movl %eax, -0xa4(%rbp)
jmp 0x115c39
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa0(%rbp)
movl %eax, -0xa4(%rbp)
jmp 0x115c2d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa0(%rbp)
movl %eax, -0xa4(%rbp)
leaq -0x1a8(%rbp), %rdi
callq 0x10bee0
leaq -0x100(%rbp), %rdi
callq 0x10bee0
leaq -0x60(%rbp), %rdi
callq 0x10bee0
movq -0xa0(%rbp), %rdi
callq 0x33a0
nop