// File: /workspace/github_cpp_makefile_star2_O3/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<-9l, -9l, -9l>>, nda::shape<nda::dim<-9l, -9l, 1l>, nda::dim<-9l, -9l, -9l>, nda::dim<-9l, -9l, -9l>>>(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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1f8, %rsp            # imm = 0x1F8
movq %rdi, %r14
movabsq $-0x8000000000000000, %rbp # imm = 0x8000000000000000
xorl %r12d, %r12d
leaq 0x58(%rsp), %r15
movq %r12, (%r15)
movl $0x28, %r13d
movq %r13, 0x8(%r15)
movq %rbp, 0x10(%r15)
xorl %edi, %edi
movq %r15, %rsi
callq 0xd133
leaq 0x148(%rsp), %rbx
xorps %xmm0, %xmm0
movups %xmm0, -0x18(%rbx)
movups %xmm0, -0x8(%rbx)
movq %r14, 0x8(%rbx)
movq %rbp, 0x10(%rbx)
movq %r12, 0x18(%rbx)
movq $0x1e, 0x20(%rbx)
movq %rbp, 0x28(%rbx)
movq %r12, 0x30(%rbx)
movq %r13, 0x38(%rbx)
leaq 0x128(%rsp), %r12
movq %r12, %rdi
callq 0xc30a
movq %r12, %rdi
callq 0xc412
movq 0x18(%r12), %rax
movq %rax, (%r15)
leaq 0x60(%rsp), %rax
movl $0x9, %ecx
movq %rax, %rdi
movq %rbx, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq %rsp, %rcx
movl $0x0, (%rcx)
leaq 0xc0(%rsp), %rsi
movq %rcx, (%rsi)
movq %r15, 0x8(%rsi)
movq %rax, %rdi
callq 0x611a0
movq 0x168(%rsp), %r15
movq 0x180(%rsp), %r12
xorl %r13d, %r13d
leaq 0xc0(%rsp), %rsi
movq %r13, (%rsi)
movq %r12, 0x8(%rsi)
movq %rbp, 0x10(%rsi)
xorl %edi, %edi
callq 0xd133
leaq 0x58(%rsp), %rdi
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rdi)
movups %xmm0, 0x18(%rdi)
movq %r14, 0x28(%rdi)
movq %rbp, 0x30(%rdi)
movq %r13, 0x38(%rdi)
movq %r15, 0x40(%rdi)
movq %rbp, 0x48(%rdi)
movq %r13, 0x50(%rdi)
movq %r12, 0x58(%rdi)
callq 0xc30a
leaq 0x58(%rsp), %rdi
callq 0xc412
leaq 0x78(%rsp), %r15
movq 0x140(%rsp), %rax
leaq 0xc8(%rsp), %rdi
movq %rax, -0x8(%rdi)
movl $0x9, %ecx
movq %rbx, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq -0x8(%r15), %rax
leaq 0x8(%rsp), %rdi
movq %rax, -0x8(%rdi)
movl $0x9, %ecx
movq %r15, %rsi
rep  movsq (%rsi), %es:(%rdi)
leaq 0xc0(%rsp), %r12
movq %rsp, %r13
movq %r12, %rdi
movq %r13, %rsi
callq 0xc9e3
xorps %xmm0, %xmm0
movaps %xmm0, (%rsp)
movq $0x0, 0x10(%rsp)
movq 0x70(%rsp), %rcx
leaq 0xc8(%rsp), %rax
movq %rcx, -0x8(%rax)
movl $0x9, %ecx
movq %rax, %rdi
movq %r15, %rsi
rep  movsq (%rsi), %es:(%rdi)
leaq 0x190(%rsp), %rsi
movq %r12, (%rsi)
movq %r13, 0x8(%rsi)
movq %rax, %rdi
callq 0x1f012
movl $0x5, %r12d
movq %rsp, %rsi
movq %r12, (%rsi)
movl $0x1e, %r13d
movq %r13, 0x8(%rsi)
movq $0x1, 0x10(%rsi)
xorl %edi, %edi
callq 0xd133
leaq 0xc0(%rsp), %rdi
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rdi)
movups %xmm0, 0x18(%rdi)
movq %r14, 0x28(%rdi)
movq %rbp, 0x30(%rdi)
movq $0x3, 0x38(%rdi)
movq $0x14, 0x40(%rdi)
movq %rbp, 0x48(%rdi)
movq %r12, 0x50(%rdi)
movq %r13, 0x58(%rdi)
callq 0xc30a
leaq 0xc0(%rsp), %rdi
callq 0xc412
movq 0x140(%rsp), %rax
leaq 0x8(%rsp), %rdi
movq %rax, -0x8(%rdi)
movl $0x9, %ecx
movq %rbx, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq 0x70(%rsp), %rax
leaq 0x198(%rsp), %rdi
movq %rax, -0x8(%rdi)
movl $0x9, %ecx
movq %r15, %rsi
rep  movsq (%rsi), %es:(%rdi)
movq %rsp, %rbx
leaq 0x190(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0xc9e3
xorps %xmm0, %xmm0
movaps %xmm0, 0x190(%rsp)
movq $0x0, 0x1a0(%rsp)
movq 0x70(%rsp), %rcx
leaq 0x8(%rsp), %rax
movq %rcx, -0x8(%rax)
movl $0x9, %ecx
movq %rax, %rdi
movq %r15, %rsi
rep  movsq (%rsi), %es:(%rdi)
leaq 0x1e8(%rsp), %rsi
movq %rbx, (%rsi)
movq %r14, 0x8(%rsi)
movq %rax, %rdi
callq 0x1f012
leaq 0xc0(%rsp), %rdi
callq 0xd206
leaq 0x58(%rsp), %rdi
callq 0xd206
leaq 0x128(%rsp), %rdi
callq 0xd206
addq $0x1f8, %rsp            # imm = 0x1F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x6cbb3
jmp 0x6cbb3
jmp 0x6cbb3
jmp 0x6cb70
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
callq 0xd206
jmp 0x6cb8d
jmp 0x6cbb3
jmp 0x6cb8a
jmp 0x6cb8a
jmp 0x6cb99
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0xd206
jmp 0x6cb9c
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
callq 0xd206
movq %rbx, %rdi
callq 0x2300
jmp 0x6cbb3
movq %rax, %rdi
callq 0xc0a9