// File: cannam[P]mini-cpp-convnet/flower.cpp
// Function: convolve(std::vector<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>, std::allocator<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>>> const&, std::vector<std::vector<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>, std::allocator<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>>>, std::allocator<std::vector<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>, std::allocator<std::vector<std::vector<float, std::allocator<float>>, std::allocator<std::vector<float, std::allocator<float>>>>>>>> const&, std::vector<float, std::allocator<float>> const&)
vector<vector<vector<float>>>
convolve(const vector<vector<vector<float>>> &in,
         const vector<vector<vector<vector<float>>>> &weights,
         const vector<float> &biases)
{
    // Weights tensor is indexed HWCK, i.e. height - width - number of
    // input channels (e.g. image depth) - number of output channels
    // (i.e. number of learned kernels)
    
    size_t kernel_height = weights.size();
    size_t kernel_width = weights[0].size();
    size_t nkernels = weights[0][0][0].size();
    
    size_t out_height = in.size();
    if (out_height < kernel_height - 1) {
        throw runtime_error("Input too small in convolve");
    }

    size_t out_width = in[0].size();
    if (out_width < kernel_width - 1) {
        throw runtime_error("Input too small in convolve");
    }

    size_t depth = in[0][0].size();
    if (depth != weights[0][0].size()) {
        cerr << "convolve: input depth is " << depth << " but we expected "
             << weights[0][0].size() << endl;
        throw runtime_error("Depth mismatch in convolve");
    }
        
    out_height -= kernel_height - 1;
    out_width -= kernel_width - 1;

#ifdef VERBOSE
    cerr << "convolve: " << nkernels << " kernels of size "
         << kernel_width << "x" << kernel_height << "; output size "
         << out_width << "x" << out_height << "; input depth " << depth << endl;
#endif

    auto out =
        vector<vector<vector<float>>>
        (out_height,
         vector<vector<float>>
         (out_width,
          vector<float>
          (nkernels,
           0.f)));

    for (size_t k = 0; k < nkernels; ++k) {
        for (size_t y = 0; y < out_height; ++y) {
            for (size_t x = 0; x < out_width; ++x) {
                for (size_t c = 0; c < depth; ++c) {
                    for (size_t ky = 0; ky < kernel_height; ++ky) {
                        for (size_t kx = 0; kx < kernel_width; ++kx) {
                            out[y][x][k] +=
                                weights[ky][kx][c][k] * in[y + ky][x + kx][c];
                        }
                    }
                }
                out[y][x][k] += biases[k];
            }
        }
    }

    return out;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movq %rdi, -0xe0(%rbp)
movq %rdi, %rax
movq %rax, -0xd8(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x4a6f0
movq %rax, -0x28(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a720
movq %rax, %rdi
callq 0x4a740
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a720
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a770
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a790
movq %rax, %rdi
callq 0x4a7b0
movq %rax, -0x38(%rbp)
movq -0x10(%rbp), %rdi
callq 0x4a740
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq -0x28(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jae 0x472bd
movl $0x10, %edi
callq 0x3120
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xe8(%rbp)
leaq 0xbdb1(%rip), %rsi      # 0x53030
callq 0x30d0
jmp 0x47286
movq -0xe8(%rbp), %rdi
movq 0xa1d5c(%rip), %rsi     # 0xe8ff0
movq 0xa1d15(%rip), %rdx     # 0xe8fb0
callq 0x3390
movq -0xe8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
callq 0x31d0
jmp 0x478ae
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a770
movq %rax, %rdi
callq 0x4a7d0
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
movq -0x30(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jae 0x47343
movl $0x10, %edi
callq 0x3120
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xf0(%rbp)
leaq 0xbd2b(%rip), %rsi      # 0x53030
callq 0x30d0
jmp 0x4730c
movq -0xf0(%rbp), %rdi
movq 0xa1cd6(%rip), %rsi     # 0xe8ff0
movq 0xa1c8f(%rip), %rdx     # 0xe8fb0
callq 0x3390
movq -0xf0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
callq 0x31d0
jmp 0x478ae
movq -0x10(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a770
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a790
movq %rax, %rdi
callq 0x4a7b0
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a720
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a770
movq %rax, %rdi
callq 0x4a7d0
movq %rax, %rcx
movq -0xf8(%rbp), %rax
cmpq %rcx, %rax
je 0x47481
movq 0xa1c3a(%rip), %rdi     # 0xe8fe8
leaq 0xbc97(%rip), %rsi      # 0x5304c
callq 0x3250
movq %rax, %rdi
movq -0x60(%rbp), %rsi
callq 0x3080
movq %rax, %rdi
leaq 0xbc96(%rip), %rsi      # 0x53066
callq 0x3250
movq %rax, -0x108(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movq %rsi, -0x110(%rbp)
callq 0x4a720
movq -0x110(%rbp), %rsi
movq %rax, %rdi
callq 0x4a770
movq %rax, %rdi
callq 0x4a7d0
movq -0x108(%rbp), %rdi
movq %rax, %rsi
callq 0x3080
movq %rax, %rdi
movq 0xa1b80(%rip), %rsi     # 0xe8fa0
callq 0x3290
movl $0x10, %edi
callq 0x3120
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x100(%rbp)
leaq 0xbc35(%rip), %rsi      # 0x53078
callq 0x30d0
jmp 0x4744a
movq -0x100(%rbp), %rdi
movq 0xa1b98(%rip), %rsi     # 0xe8ff0
movq 0xa1b51(%rip), %rdx     # 0xe8fb0
callq 0x3390
movq -0x100(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
callq 0x31d0
jmp 0x478ae
movq -0x28(%rbp), %rcx
movq -0x40(%rbp), %rax
subq %rcx, %rax
incq %rax
movq %rax, -0x40(%rbp)
movq -0x30(%rbp), %rcx
movq -0x58(%rbp), %rax
subq %rcx, %rax
incq %rax
movq %rax, -0x58(%rbp)
movb $0x0, -0x61(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x130(%rbp)
movq -0x58(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x120(%rbp)
movl $0x0, -0x9c(%rbp)
leaq -0x9d(%rbp), %rdi
movq %rdi, -0x118(%rbp)
callq 0x4a800
movq -0x120(%rbp), %rsi
movq -0x118(%rbp), %rcx
leaq -0x98(%rbp), %rdi
leaq -0x9c(%rbp), %rdx
callq 0x4a820
jmp 0x4750a
leaq -0x9e(%rbp), %rdi
movq %rdi, -0x138(%rbp)
callq 0x4a8a0
movq -0x128(%rbp), %rsi
movq -0x138(%rbp), %rcx
leaq -0x80(%rbp), %rdi
leaq -0x98(%rbp), %rdx
callq 0x4a8c0
jmp 0x4753d
leaq -0x9f(%rbp), %rdi
movq %rdi, -0x140(%rbp)
callq 0x4a940
movq -0xe0(%rbp), %rdi
movq -0x130(%rbp), %rsi
movq -0x140(%rbp), %rcx
leaq -0x80(%rbp), %rdx
callq 0x4a960
jmp 0x47570
leaq -0x9f(%rbp), %rdi
callq 0x4a9e0
leaq -0x80(%rbp), %rdi
callq 0x4aa00
leaq -0x9e(%rbp), %rdi
callq 0x4aa60
leaq -0x98(%rbp), %rdi
callq 0x4aa80
leaq -0x9d(%rbp), %rdi
callq 0x4aae0
movq $0x0, -0xa8(%rbp)
movq -0xa8(%rbp), %rax
cmpq -0x38(%rbp), %rax
jae 0x47888
movq $0x0, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
cmpq -0x40(%rbp), %rax
jae 0x4786f
movq $0x0, -0xb8(%rbp)
movq -0xb8(%rbp), %rax
cmpq -0x58(%rbp), %rax
jae 0x47856
movq $0x0, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
cmpq -0x60(%rbp), %rax
jae 0x477e2
movq $0x0, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpq -0x28(%rbp), %rax
jae 0x477c9
movq $0x0, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
cmpq -0x30(%rbp), %rax
jae 0x477b0
movq -0x18(%rbp), %rdi
movq -0xc8(%rbp), %rsi
callq 0x4a720
movq %rax, %rdi
movq -0xd0(%rbp), %rsi
callq 0x4a770
movq %rax, %rdi
movq -0xc0(%rbp), %rsi
callq 0x4a790
movq %rax, %rdi
movq -0xa8(%rbp), %rsi
callq 0x4ab00
movss (%rax), %xmm0
movss %xmm0, -0x148(%rbp)
movq -0x10(%rbp), %rdi
movq -0xb0(%rbp), %rsi
addq -0xc8(%rbp), %rsi
callq 0x4a770
movq %rax, %rdi
movq -0xb8(%rbp), %rsi
addq -0xd0(%rbp), %rsi
callq 0x4a790
movq %rax, %rdi
movq -0xc0(%rbp), %rsi
callq 0x4ab00
movq -0xe0(%rbp), %rdi
movss (%rax), %xmm0
movss %xmm0, -0x144(%rbp)
movq -0xb0(%rbp), %rsi
callq 0x4ab20
movq %rax, %rdi
movq -0xb8(%rbp), %rsi
callq 0x4ab40
movq %rax, %rdi
movq -0xa8(%rbp), %rsi
callq 0x4ab60
movss -0x148(%rbp), %xmm0
movss -0x144(%rbp), %xmm2
movss (%rax), %xmm1
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
movss %xmm0, (%rax)
movq -0xd0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xd0(%rbp)
jmp 0x47640
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x4779f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
jmp 0x47787
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x48(%rbp)
movl %eax, -0x4c(%rbp)
leaq -0x9f(%rbp), %rdi
callq 0x4a9e0
leaq -0x80(%rbp), %rdi
callq 0x4aa00
leaq -0x9e(%rbp), %rdi
callq 0x4aa60
leaq -0x98(%rbp), %rdi
callq 0x4aa80
leaq -0x9d(%rbp), %rdi
callq 0x4aae0
jmp 0x478ae
jmp 0x477b2
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0x47624
jmp 0x477cb
movq -0xc0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc0(%rbp)
jmp 0x47608
movq -0x20(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x4ab00
movq -0xe0(%rbp), %rdi
movss (%rax), %xmm0
movss %xmm0, -0x14c(%rbp)
movq -0xb0(%rbp), %rsi
callq 0x4ab20
movq %rax, %rdi
movq -0xb8(%rbp), %rsi
callq 0x4ab40
movq %rax, %rdi
movq -0xa8(%rbp), %rsi
callq 0x4ab60
movss -0x14c(%rbp), %xmm0
addss (%rax), %xmm0
movss %xmm0, (%rax)
movq -0xb8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb8(%rbp)
jmp 0x475ec
jmp 0x47858
movq -0xb0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
jmp 0x475d0
jmp 0x47871
movq -0xa8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xa8(%rbp)
jmp 0x475b4
movb $0x1, -0x61(%rbp)
testb $0x1, -0x61(%rbp)
jne 0x4789e
movq -0xe0(%rbp), %rdi
callq 0x4ab80
movq -0xd8(%rbp), %rax
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
movq -0x48(%rbp), %rdi
callq 0x33b0
nopw (%rax,%rax)