// File: /workspace/github_cpp_makefile_star2_O2/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 $0xb8, %rsp
movq %r8, 0x30(%rsp)
movq %rcx, 0x40(%rsp)
movq %rdi, %r12
cmpl %edx, %esi
movl %edx, %eax
movl %esi, 0x24(%rsp)
cmovll %esi, %eax
movsd (%rdi), %xmm3
leal 0x1(%rdx), %esi
movl %eax, 0x14(%rsp)
movslq %eax, %rbp
movq %rdx, 0x18(%rsp)
movslq %edx, %r9
leaq 0x8(%rdi), %rax
leaq 0x8(,%r9,8), %rcx
pushq $0x1
popq %rdx
movapd 0x2bcc1(%rip), %xmm0    # 0x93270
movl %esi, 0x10(%rsp)
cmpq %rbp, %rdx
jge 0x675e5
movslq %esi, %rsi
movsd (%r12,%rsi,8), %xmm1
andpd %xmm0, %xmm1
movsd (%rax), %xmm2
andpd %xmm0, %xmm2
addsd %xmm1, %xmm2
maxsd %xmm3, %xmm2
incq %rdx
addq %rcx, %rax
addl 0x10(%rsp), %esi
movapd %xmm2, %xmm3
jmp 0x675b3
movabsq $-0x100000000, %r10     # imm = 0xFFFFFFFF00000000
leal -0x1(%rbp), %eax
movslq %eax, %r15
xorl %eax, %eax
testl %r9d, %r9d
cmovgl 0x18(%rsp), %eax
movq %rax, 0x90(%rsp)
movq %r15, %rax
shlq $0x20, %rax
movq %rax, 0x58(%rsp)
pushq $0x1
popq %rdx
subl %ebp, %edx
movq %r15, %rsi
notq %rsi
leaq -0x1(%r15), %rcx
imulq %r9, %rcx
leaq (,%r15,8), %rax
movq %rcx, 0x50(%rsp)
leaq (%rax,%rcx,8), %rax
addq %r12, %rax
movq %rax, 0x48(%rsp)
leaq (,%r9,8), %rdi
movq %rdi, %r13
xorq $-0x8, %r13
leaq -0x1(%rbp), %rax
movq %rax, %rcx
subq %r15, %rcx
movq %rcx, 0x88(%rsp)
movl 0x10(%rsp), %ecx
imull %r15d, %ecx
movl %ecx, 0x10(%rsp)
movl %r9d, %ebx
notl %ebx
imulq %r9, %rax
movq 0x30(%rsp), %rcx
leaq (%rcx,%rax,8), %rax
movq %rax, 0x28(%rsp)
movq %rdx, %rax
negq %rdi
movq %rdi, 0x70(%rsp)
movl 0x14(%rsp), %ecx
movl %ecx, 0x20(%rsp)
movq %r9, 0xb0(%rsp)
movsd %xmm3, 0xa8(%rsp)
movq %r12, 0xa0(%rsp)
testq %rbp, %rbp
jle 0x678e4
decq %rbp
decl 0x20(%rsp)
movq %rax, 0x80(%rsp)
negq %rax
movq %rax, 0x60(%rsp)
movq %rsi, 0x78(%rsp)
negq %rsi
movq %rsi, 0x98(%rsp)
xorl %r11d, %r11d
movq %rbp, 0x68(%rsp)
cmpl $0x64, %r11d
je 0x678a7
movq 0x50(%rsp), %rdi
movq 0x48(%rsp), %rcx
xorl %esi, %esi
movq 0x58(%rsp), %r8
movq %r8, %rax
movq %rsi, %r14
addq %r15, %rsi
testq %rsi, %rsi
jle 0x67742
movq %rdi, %rdx
movsd (%rcx), %xmm0
addsd %xmm3, %xmm0
leaq (%rax,%r10), %r8
leaq -0x1(%r14), %rsi
addq %r13, %rcx
subq %r9, %rdi
ucomisd %xmm3, %xmm0
jne 0x67702
jp 0x67702
leaq (%r12,%rdx,8), %rcx
addq 0x98(%rsp), %rsi
andq $0x0, (%rcx,%rsi,8)
testl %r14d, %r14d
je 0x67854
addq 0x60(%rsp), %r14
sarq $0x20, %rax
movl 0x10(%rsp), %ecx
xorl %esi, %esi
movl %r11d, 0x3c(%rsp)
leaq (%r15,%rsi), %rdx
cmpq %rax, %rdx
jl 0x677b2
movslq %ecx, %rdx
movsd (%r12,%rdx,8), %xmm0
addsd %xmm3, %xmm0
ucomisd %xmm3, %xmm0
jne 0x6777d
jnp 0x67784
decq %rsi
addl %ebx, %ecx
jmp 0x6775f
movq %r15, %rax
addq %rsi, %rax
js 0x677b2
cmpq %rsi, 0x88(%rsp)
jne 0x6782d
movq %r12, %rdi
xorl %esi, %esi
movl %ebp, %edx
movq 0x30(%rsp), %rcx
movq 0x18(%rsp), %r9
callq 0x66dcd
jmp 0x67805
movq %r12, %rdi
movl %r14d, %esi
movl %ebp, %edx
movq 0x30(%rsp), %rbp
movq %rbp, %rcx
movq 0x18(%rsp), %r12
movl %r12d, %r9d
callq 0x67132
movl 0x14(%rsp), %eax
movl %eax, 0x8(%rsp)
movl %r12d, (%rsp)
movq 0xa0(%rsp), %r12
movq %r12, %rdi
movl %r14d, %esi
movq 0x68(%rsp), %rdx
movq 0x40(%rsp), %rcx
movq %rbp, %r8
movq 0x68(%rsp), %rbp
movl 0x24(%rsp), %r9d
callq 0x66f27
movl 0x3c(%rsp), %r11d
incl %r11d
movq 0xb0(%rsp), %r9
movsd 0xa8(%rsp), %xmm3
movabsq $-0x100000000, %r10     # imm = 0xFFFFFFFF00000000
jmp 0x676e7
addq 0x60(%rsp), %rsi
movl 0x14(%rsp), %eax
movl %eax, (%rsp)
movq %r12, %rdi
movl %ebp, %edx
movq 0x40(%rsp), %rcx
movl 0x24(%rsp), %r8d
movq 0x18(%rsp), %r9
callq 0x66c7b
jmp 0x67805
movl 0x20(%rsp), %eax
imull 0x18(%rsp), %eax
cltq
leaq (%r12,%rbp,8), %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm1
jbe 0x678a7
xorpd 0x2b7b6(%rip), %xmm0    # 0x93030
movlpd %xmm0, (%rcx,%rax,8)
xorl %eax, %eax
cmpq %rax, 0x90(%rsp)
je 0x678a7
movq 0x28(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd 0x2b793(%rip), %xmm0    # 0x93030
movlpd %xmm0, (%rcx,%rax,8)
incq %rax
jmp 0x67881
decq %r15
addq %r10, 0x58(%rsp)
movq 0x80(%rsp), %rax
incq %rax
movq 0x78(%rsp), %rsi
incq %rsi
addq %r13, 0x48(%rsp)
subq %r9, 0x50(%rsp)
addl %ebx, 0x10(%rsp)
movq 0x28(%rsp), %rcx
addq 0x70(%rsp), %rcx
movq %rcx, 0x28(%rsp)
jmp 0x676af
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq