// File: markondej[P]phase_correl/phase_correl.c
// Function: fft2D
void fft2D(double *data, unsigned width, unsigned height, int inverse) {
    unsigned i, j;

    double *fft_input = (double *)malloc((sizeof(double) * width) << 1);
    double *fft_output = (double *)malloc((sizeof(double) * width) << 1);

    if (inverse) {
        goto horizontal_fft;
    }

vertical_fft:
    for (j = 0; j < height; j++) {
        unsigned offset = j * width;
        for (i = 0; i < width; i++) {
            fft_input[i << 1] = data[offset << 1];
            fft_input[(i << 1) + 1] = data[(offset << 1) + 1];
            offset++;
        }
        dit2fft(fft_input, fft_output, width, inverse);
        offset = j * width;
        for (i = 0; i < width; i++) {
            data[offset << 1] = fft_output[i << 1];
            data[(offset << 1) + 1] = fft_output[(i << 1) + 1];
            offset++;
        }
    }

    if (inverse) {
        goto done;
    }

horizontal_fft:
    for (i = 0; i < width; i++) {
        unsigned offset = i;
        for (j = 0; j < height; j++) {
            fft_input[j << 1] = data[offset << 1];
            fft_input[(j << 1) + 1] = data[(offset << 1) + 1];
            offset += width;
        }
        dit2fft(fft_input, fft_output, height, inverse);
        offset = i;
        for (j = 0; j < height; j++) {
            data[offset << 1] = fft_output[j << 1];
            data[(offset << 1) + 1] = fft_output[(j << 1) + 1];
            offset += width;
        }
    }

    if (inverse) {
        goto vertical_fft;
    }

done:
    free(fft_input);
    free(fft_output);
}

// Assembly:
subq $0x38, %rsp
movq %rdi, 0x30(%rsp)
movl %esi, 0x2c(%rsp)
movl %edx, 0x28(%rsp)
movl %ecx, 0x24(%rsp)
movl 0x2c(%rsp), %eax
movl %eax, %edi
shlq $0x3, %rdi
shlq %rdi
callq 0x1090
movq %rax, 0x10(%rsp)
movl 0x2c(%rsp), %eax
movl %eax, %edi
shlq $0x3, %rdi
shlq %rdi
callq 0x1090
movq %rax, 0x8(%rsp)
cmpl $0x0, 0x24(%rsp)
je 0x17af
jmp 0x1908
jmp 0x17b1
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
cmpl 0x28(%rsp), %eax
jae 0x18fa
movl 0x1c(%rsp), %eax
imull 0x2c(%rsp), %eax
movl %eax, 0x4(%rsp)
movl $0x0, 0x20(%rsp)
movl 0x20(%rsp), %eax
cmpl 0x2c(%rsp), %eax
jae 0x184c
movq 0x30(%rsp), %rax
movl 0x4(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x10(%rsp), %rax
movl 0x20(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movq 0x30(%rsp), %rax
movl 0x4(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x10(%rsp), %rax
movl 0x20(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movl 0x4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4(%rsp)
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x17dc
movq 0x10(%rsp), %rdi
movq 0x8(%rsp), %rsi
movl 0x2c(%rsp), %edx
movl 0x24(%rsp), %ecx
callq 0x15d0
movl 0x1c(%rsp), %eax
imull 0x2c(%rsp), %eax
movl %eax, 0x4(%rsp)
movl $0x0, 0x20(%rsp)
movl 0x20(%rsp), %eax
cmpl 0x2c(%rsp), %eax
jae 0x18e8
movq 0x8(%rsp), %rax
movl 0x20(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x30(%rsp), %rax
movl 0x4(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movq 0x8(%rsp), %rax
movl 0x20(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x30(%rsp), %rax
movl 0x4(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movl 0x4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4(%rsp)
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x1878
jmp 0x18ea
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x17b9
cmpl $0x0, 0x24(%rsp)
je 0x1906
jmp 0x1a4d
jmp 0x1908
movl $0x0, 0x20(%rsp)
movl 0x20(%rsp), %eax
cmpl 0x2c(%rsp), %eax
jae 0x1a3f
movl 0x20(%rsp), %eax
movl %eax, (%rsp)
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
cmpl 0x28(%rsp), %eax
jae 0x199a
movq 0x30(%rsp), %rax
movl (%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x10(%rsp), %rax
movl 0x1c(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movq 0x30(%rsp), %rax
movl (%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x10(%rsp), %rax
movl 0x1c(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movl 0x2c(%rsp), %eax
addl (%rsp), %eax
movl %eax, (%rsp)
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x192d
movq 0x10(%rsp), %rdi
movq 0x8(%rsp), %rsi
movl 0x28(%rsp), %edx
movl 0x24(%rsp), %ecx
callq 0x15d0
movl 0x20(%rsp), %eax
movl %eax, (%rsp)
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
cmpl 0x28(%rsp), %eax
jae 0x1a2d
movq 0x8(%rsp), %rax
movl 0x1c(%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x30(%rsp), %rax
movl (%rsp), %ecx
shll %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movq 0x8(%rsp), %rax
movl 0x1c(%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd (%rax,%rcx,8), %xmm0
movq 0x30(%rsp), %rax
movl (%rsp), %ecx
shll %ecx
addl $0x1, %ecx
movl %ecx, %ecx
movsd %xmm0, (%rax,%rcx,8)
movl 0x2c(%rsp), %eax
addl (%rsp), %eax
movl %eax, (%rsp)
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x19c0
jmp 0x1a2f
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x1910
cmpl $0x0, 0x24(%rsp)
je 0x1a4b
jmp 0x17b1
jmp 0x1a4d
movq 0x10(%rsp), %rdi
callq 0x1030
movq 0x8(%rsp), %rdi
callq 0x1030
addq $0x38, %rsp
retq
nopw %cs:(%rax,%rax)