// File: WeihuaZhu[P]hpc_prog2/jacobi.cpp
// Function: jacobi(int, double*, double*, double*, int, double)
void jacobi(const int n, double* A, double* b, double* x, int max_iter, double l2_termination)
{
    for (int i = 0; i < n; i++) x[i] = 0;

    double* D = (double *) malloc(sizeof(double)*(n*n));
    double* R = (double *) malloc(sizeof(double)*(n*n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (i == j) {
                D[i*n+j] = A[i*n+j];
                R[i*n+j] = 0;
            } else {
                D[i*n+j] = 0;
                R[i*n+j] = A[i*n+j];
            }
        }
    }

    for (int iter = 0; iter < max_iter; iter++) {
        //calculate 2 norm
        double* sol = (double *) malloc(sizeof(double)*n);
        matrix_vector_mult(n, A, x, sol);
        for (int i = 0; i < n; i++) {
            sol[i] -= b[i];
        }
        double sol2;
        matrix_vector_mult(1, n, sol, sol, &sol2);
        double _2norm = sqrt(sol2);
        free(sol);

        if (_2norm > l2_termination) {
            double* b_Rx = (double *) malloc(sizeof(double)*n);
            matrix_vector_mult(n, R, x, b_Rx);
            for(int i = 0; i < n; i++){
                x[i] = (b[i] - b_Rx[i])/D[i*n+i];
            }
            free(b_Rx);
        } else {
            break;
        }
    }

    free(D);
    free(R);
}

// Assembly:
subq $0x88, %rsp
movl %edi, 0x84(%rsp)
movq %rsi, 0x78(%rsp)
movq %rdx, 0x70(%rsp)
movq %rcx, 0x68(%rsp)
movl %r8d, 0x64(%rsp)
movsd %xmm0, 0x58(%rsp)
movl $0x0, 0x54(%rsp)
movl 0x54(%rsp), %eax
cmpl 0x84(%rsp), %eax
jge 0x4a9bc
movq 0x68(%rsp), %rax
movslq 0x54(%rsp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x54(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x54(%rsp)
jmp 0x4a990
movl 0x84(%rsp), %eax
imull 0x84(%rsp), %eax
movslq %eax, %rdi
shlq $0x3, %rdi
callq 0xeef0
movq %rax, 0x48(%rsp)
movl 0x84(%rsp), %eax
imull 0x84(%rsp), %eax
movslq %eax, %rdi
shlq $0x3, %rdi
callq 0xeef0
movq %rax, 0x40(%rsp)
movl $0x0, 0x3c(%rsp)
movl 0x3c(%rsp), %eax
cmpl 0x84(%rsp), %eax
jge 0x4ab12
movl $0x0, 0x38(%rsp)
movl 0x38(%rsp), %eax
cmpl 0x84(%rsp), %eax
jge 0x4ab00
movl 0x3c(%rsp), %eax
cmpl 0x38(%rsp), %eax
jne 0x4aa94
movq 0x78(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x48(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
movq 0x40(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
jmp 0x4aaee
movq 0x48(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movq 0x78(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x40(%rsp), %rax
movl 0x3c(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x38(%rsp), %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
jmp 0x4aaf0
movl 0x38(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x38(%rsp)
jmp 0x4aa1d
jmp 0x4ab02
movl 0x3c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3c(%rsp)
jmp 0x4aa04
movl $0x0, 0x34(%rsp)
movl 0x34(%rsp), %eax
cmpl 0x64(%rsp), %eax
jge 0x4acac
movslq 0x84(%rsp), %rdi
shlq $0x3, %rdi
callq 0xeef0
movq %rax, 0x28(%rsp)
movl 0x84(%rsp), %edi
movq 0x78(%rsp), %rsi
movq 0x68(%rsp), %rdx
movq 0x28(%rsp), %rcx
callq 0x4a7e0
movl $0x0, 0x24(%rsp)
movl 0x24(%rsp), %eax
cmpl 0x84(%rsp), %eax
jge 0x4aba2
movq 0x70(%rsp), %rax
movslq 0x24(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
movq 0x28(%rsp), %rax
movslq 0x24(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
subsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x4ab61
movl 0x84(%rsp), %esi
movq 0x28(%rsp), %rdx
movq 0x28(%rsp), %rcx
movl $0x1, %edi
leaq 0x18(%rsp), %r8
callq 0x4a8a0
movsd 0x18(%rsp), %xmm0
callq 0xe7a0
movsd %xmm0, 0x10(%rsp)
movq 0x28(%rsp), %rdi
callq 0xed00
movsd 0x10(%rsp), %xmm0
ucomisd 0x58(%rsp), %xmm0
jbe 0x4ac98
movslq 0x84(%rsp), %rdi
shlq $0x3, %rdi
callq 0xeef0
movq %rax, 0x8(%rsp)
movl 0x84(%rsp), %edi
movq 0x40(%rsp), %rsi
movq 0x68(%rsp), %rdx
movq 0x8(%rsp), %rcx
callq 0x4a7e0
movl $0x0, 0x4(%rsp)
movl 0x4(%rsp), %eax
cmpl 0x84(%rsp), %eax
jge 0x4ac8c
movq 0x70(%rsp), %rax
movslq 0x4(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x8(%rsp), %rax
movslq 0x4(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm0
movq 0x48(%rsp), %rax
movl 0x4(%rsp), %ecx
imull 0x84(%rsp), %ecx
addl 0x4(%rsp), %ecx
movslq %ecx, %rcx
divsd (%rax,%rcx,8), %xmm0
movq 0x68(%rsp), %rax
movslq 0x4(%rsp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl 0x4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4(%rsp)
jmp 0x4ac28
movq 0x8(%rsp), %rdi
callq 0xed00
jmp 0x4ac9a
jmp 0x4acac
jmp 0x4ac9c
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0x4ab1a
movq 0x48(%rsp), %rdi
callq 0xed00
movq 0x40(%rsp), %rdi
callq 0xed00
addq $0x88, %rsp
retq