// File: /workspace/github_cpp_makefile_star2_O3/tomfunkhouser[P]gaps/pkgs/RNBasics/RNSvd.cpp
// Function: gaps::bidiagonal_svd(double*, int, int, double*, double*)
void bidiagonal_svd(RNScalar *b,int m,int n,RNScalar *u,RNScalar *v)
{
    RNScalar anorm, t;
    int p, q, i, j, z, iter, min=MIN(m,n);

    /* use the max of the sum of each diagonal element and the
    ** superdiagonal element above it as a norm for the array.
    ** The use of this norm comes from the Numerical Recipes (Press et al)
    ** code.  squawk!
    */

    // CHUCKR: this is where the array access if fouling up
    //for (anorm=REF2D(b,m,n,0,0), i=1; i<n; i++) {
    for (anorm = REF2D(b,m,n,0,0), i=1 ; i < min ; i++) 
    {
	    t = ((RNScalar) (fabs(REF2D(b,m,n,i,i)) + fabs(REF2D(b,m,n,i-1,i))));

	    if (t > anorm) 
            anorm = t;
    }

    /* Each iteration of this loop will zero out the superdiagonal
    ** element above b[q][q] -- i.e. b[q][q] will be a singular value.
    */
    for (q = min-1; q>=0; q--) {

	/* Each iteration will make the superdiagonal elements smaller,
	** till they drop below numerical noise.  It ought to converge
	** by 30 tries.  squawk!  (Increased to 100 tries by funk)
	*/
        const int max_iter = 100;
	for (iter=0; iter<max_iter; iter++) {
	    
	    /* Find a block that has a zero on the diagonal or superdiagonal.
	    ** That is, we are breaking up b into three submatrices,
	    ** b11, b22, b33, such that b33 is diagonal and b22 has no zeros 
	    ** on the superdiagonal.
	    ** b33 goes from q+1 to n-1 -- it's the part we already did
	    ** b22 goes from p through q -- it's a bidiagonal block
	    */

	    /* sweep back till we reach a numerically 0 superdiagonal element */
	    for (p = q; p>0; p--) if (REF2D(b,m,n,p-1,p) + anorm == anorm) {
		REF2D(b,m,n,p-1,p) = 0;
		break;
	    }

	    /* if b22 is 1x1, i.e. there is a 0 above b[q,q], then
	    ** b[q,q] is the singular value.  Go on to the next
	    ** singular value.  (But first, make sure it's
	    ** positive.  If it's negative, negate it and the
	    ** corresponding row of v)
	    */

	    if (p==q) {
		if (REF2D(b,m,n,q,q) < 0) {
		    REF2D(b,m,n,q,q) *= -1;
		    for (j=0; j<n; j++) REF2D(v,min,n,q,j) *= -1;
		}
		break;
	    }

	    /* check for zero on the diagonal */
	    for (z= -1, i=q; i>=p; i--) if (REF2D(b,m,n,i,i)+anorm==anorm) {
		z = i;
		break;
	    }
	    if (z >= 0) {
		/* get rid of zero on the diagonl.  where is it? */
		if (z == q)
		    /* lower-right corner.  clr element above it */
		    clr_bot_supdiag_elt(b,0,z,v,m,n,min);
		else
		    /* in the middle.  clr elt to its right */
		    clr_top_supdiag_elt(b,z,q,u,m,n,min);
	    }
	    else {
		/* b22 has no zeroes on the diagonal or superdiagonal.
		** Do magic rotation, leaving glop in the uppermost
		** subdiagonal element
		*/
		golub_kahn_svd_rot(b,p,q,v,m,n,min);
		/* get rid of the glop in the uppermost subdiagonal */
		clr_top_subdiag_elt(b,p,q,u,v,m,n,min);
	    }
	}
#if 0
	if (iter>=max_iter)
	    (void) fprintf(stderr,"svd: didn't converge after %d iterations\n", max_iter);
#endif
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %r8, 0x40(%rsp)
movq %rcx, 0x50(%rsp)
movq %rdi, %r13
cmpl %edx, %esi
movl %edx, %r9d
movl %esi, 0x24(%rsp)
cmovll %esi, %r9d
movsd (%rdi), %xmm1
cmpl $0x2, %r9d
jl 0x70dd0
leal 0x1(%rdx), %eax
movl %r9d, %ecx
leaq 0x8(%r13), %r8
decq %rcx
xorl %esi, %esi
movapd 0x314d8(%rip), %xmm0    # 0xa2270
movl %eax, %edi
movslq %esi, %rsi
movslq %edi, %rdi
movsd (%r13,%rdi,8), %xmm2
andpd %xmm0, %xmm2
movsd (%r8,%rsi,8), %xmm3
andpd %xmm0, %xmm3
addsd %xmm2, %xmm3
maxsd %xmm1, %xmm3
addq $0x8, %r8
addl %edx, %esi
addl %eax, %edi
movapd %xmm3, %xmm1
decq %rcx
jne 0x70d9a
jmp 0x70dd4
movapd %xmm1, %xmm3
movq %rdx, 0x28(%rsp)
movl %r9d, 0x20(%rsp)
testl %r9d, %r9d
jle 0x710a4
movabsq $-0x100000000, %r12     # imm = 0xFFFFFFFF00000000
movq 0x28(%rsp), %rdx
leal 0x1(%rdx), %eax
movslq %edx, %rbx
movl 0x24(%rsp), %ecx
cmpl %ecx, %edx
cmovll %edx, %ecx
movslq %ecx, %rdi
movl %edx, %ecx
movq %rcx, 0x78(%rsp)
movq %rdi, %rcx
shlq $0x20, %rcx
addq %r12, %rcx
movq %rcx, 0x68(%rsp)
leaq -0x2(%rdi), %rsi
imulq %rbx, %rsi
leaq (,%rdi,8), %rcx
movq %rsi, 0x60(%rsp)
leaq (%rcx,%rsi,8), %rcx
addq %r13, %rcx
addq $-0x8, %rcx
movq %rcx, 0x58(%rsp)
leaq (,%rbx,8), %rsi
movq %rsi, %r15
xorq $-0x8, %r15
leal -0x1(%rdi), %ecx
imull %eax, %ecx
movl %ecx, 0x34(%rsp)
movl %edx, %r8d
notl %r8d
movq %rdi, 0x18(%rsp)
leaq -0x1(%rdi), %rax
imulq %rbx, %rax
movq 0x40(%rsp), %rcx
leaq (%rcx,%rax,8), %rax
movq %rax, 0x38(%rsp)
negq %rsi
movq %rsi, 0x70(%rsp)
movl 0x20(%rsp), %eax
movl %eax, 0x30(%rsp)
movapd %xmm3, 0x90(%rsp)
movl %r8d, 0x4c(%rsp)
movq %r13, 0x80(%rsp)
movq 0x18(%rsp), %r9
leaq -0x1(%r9), %rax
movq %rax, 0x18(%rsp)
decl 0x30(%rsp)
xorl %ebp, %ebp
movq %r9, 0x88(%rsp)
movq 0x60(%rsp), %rsi
movq 0x58(%rsp), %rcx
movq %r9, %r14
movq 0x68(%rsp), %rdi
movq %rdi, %rax
decq %r14
testq %r14, %r14
jle 0x70f0c
movq %rsi, %rdx
movsd (%rcx), %xmm0
addsd %xmm3, %xmm0
leaq (%rax,%r12), %rdi
addq %r15, %rcx
subq %rbx, %rsi
ucomisd %xmm3, %xmm0
jne 0x70ed1
jp 0x70ed1
leaq (,%rdx,8), %rcx
addq %r13, %rcx
movq $0x0, (%rcx,%r14,8)
movl %r14d, %ecx
cmpq 0x18(%rsp), %rcx
je 0x7101d
sarq $0x20, %rax
movl 0x34(%rsp), %ecx
movq %r9, %rdx
cmpq %rax, %r9
jle 0x70f75
movslq %ecx, %rsi
movsd (%r13,%rsi,8), %xmm0
addsd %xmm3, %xmm0
ucomisd %xmm3, %xmm0
jne 0x70f40
jnp 0x70f4d
decq %rdx
addl %r8d, %ecx
cmpq %rax, %rdx
jg 0x70f2a
jmp 0x70f75
decq %rdx
js 0x70f75
movl %edx, %eax
cmpq 0x18(%rsp), %rax
jne 0x70ff6
movq %r13, %rdi
xorl %esi, %esi
movq 0x40(%rsp), %rcx
movq 0x28(%rsp), %r9
callq 0x704be
jmp 0x70fd0
movq %r13, %rdi
movl %r14d, %esi
movq 0x18(%rsp), %rdx
movq 0x40(%rsp), %r12
movq %r12, %rcx
movq 0x28(%rsp), %r13
movl %r13d, %r9d
callq 0x708e2
movl 0x20(%rsp), %eax
movl %eax, 0x8(%rsp)
movl %r13d, (%rsp)
movq 0x80(%rsp), %r13
movq %r13, %rdi
movl %r14d, %esi
movq 0x18(%rsp), %rdx
movq 0x50(%rsp), %rcx
movq %r12, %r8
movabsq $-0x100000000, %r12     # imm = 0xFFFFFFFF00000000
movl 0x24(%rsp), %r9d
callq 0x70620
incl %ebp
cmpl $0x64, %ebp
movapd 0x90(%rsp), %xmm3
movl 0x4c(%rsp), %r8d
movq 0x88(%rsp), %r9
jne 0x70ebf
jmp 0x71077
movl 0x20(%rsp), %eax
movl %eax, (%rsp)
movq %r13, %rdi
movl %edx, %esi
movq 0x18(%rsp), %rdx
movq 0x50(%rsp), %rcx
movl 0x24(%rsp), %r8d
movq 0x28(%rsp), %r9
callq 0x70364
jmp 0x70fd0
movl 0x30(%rsp), %eax
imull 0x28(%rsp), %eax
cltq
movq 0x18(%rsp), %rcx
leaq (,%rcx,8), %rcx
addq %r13, %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm1
jbe 0x71077
xorpd 0x30fd1(%rip), %xmm0    # 0xa2020
movlpd %xmm0, (%rcx,%rax,8)
xorl %eax, %eax
movq 0x38(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd 0x30fb8(%rip), %xmm0    # 0xa2020
movlpd %xmm0, (%rcx,%rax,8)
incq %rax
cmpq %rax, 0x78(%rsp)
jne 0x71056
addq %r12, 0x68(%rsp)
addq %r15, 0x58(%rsp)
subq %rbx, 0x60(%rsp)
addl %r8d, 0x34(%rsp)
movq 0x38(%rsp), %rax
addq 0x70(%rsp), %rax
movq %rax, 0x38(%rsp)
cmpq $0x1, %r9
jg 0x70ea3
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq