// File: /workspace/github_cpp_makefile_star2_O1/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 $0x98, %rsp
movq %r8, 0x28(%rsp)
movq %rcx, 0x38(%rsp)
movl %edx, %r12d
cmpl %edx, %esi
movl %edx, %r9d
movl %esi, 0x1c(%rsp)
cmovll %esi, %r9d
movsd (%rdi), %xmm1
cmpl $0x2, %r9d
jl 0x71e22
leal 0x1(%r12), %eax
movl %r9d, %ecx
leaq 0x8(%rdi), %rdx
decq %rcx
xorl %esi, %esi
movapd 0x30487(%rip), %xmm0    # 0xa2270
movl %eax, %r8d
movslq %esi, %rsi
movslq %r8d, %r8
movsd (%rdi,%r8,8), %xmm2
andpd %xmm0, %xmm2
movsd (%rdx,%rsi,8), %xmm3
andpd %xmm0, %xmm3
addsd %xmm2, %xmm3
maxsd %xmm1, %xmm3
addq $0x8, %rdx
addl %r12d, %esi
addl %eax, %r8d
movapd %xmm3, %xmm1
decq %rcx
jne 0x71dec
jmp 0x71e26
movapd %xmm1, %xmm3
movl %r9d, 0x18(%rsp)
testl %r9d, %r9d
jle 0x720ab
movabsq $-0x100000000, %r8      # imm = 0xFFFFFFFF00000000
leal 0x1(%r12), %eax
movl 0x1c(%rsp), %ecx
cmpl %ecx, %r12d
cmovll %r12d, %ecx
movslq %ecx, %r10
movslq %r12d, %r9
movl %r12d, %ecx
movq %rcx, 0x70(%rsp)
movq %r10, %rcx
shlq $0x20, %rcx
addq %r8, %rcx
movq %rcx, 0x50(%rsp)
leaq -0x1(%r10), %rcx
imulq %r9, %rcx
leaq (%r10,%rcx), %rdx
movq %rdx, 0x48(%rsp)
movq %r9, %rbx
notq %rbx
leaq -0x2(%r10), %rdx
imulq %r9, %rdx
leaq (,%r10,8), %rsi
leaq (%rsi,%rdx,8), %rdx
addq %rdi, %rdx
addq $-0x8, %rdx
movq %rdx, 0x40(%rsp)
shlq $0x3, %r9
movq %r9, %r15
xorq $-0x8, %r15
leal -0x1(%r10), %edx
imull %eax, %edx
movl %edx, 0x24(%rsp)
movl %r12d, %r13d
notl %r13d
movq 0x28(%rsp), %rax
leaq (%rax,%rcx,8), %rax
movq %rax, 0x30(%rsp)
negq %r9
movq %r9, 0x68(%rsp)
movl 0x18(%rsp), %eax
movl %eax, 0x20(%rsp)
movq %rdi, 0x58(%rsp)
movapd %xmm3, 0x80(%rsp)
movq %r10, %r9
decq %r10
decl 0x20(%rsp)
xorl %ebp, %ebp
movq %r10, 0x60(%rsp)
movq %r9, 0x78(%rsp)
movq 0x40(%rsp), %rdx
movq 0x48(%rsp), %rcx
movq %r9, %r14
movq 0x50(%rsp), %rsi
movq %rsi, %rax
decq %r14
testq %r14, %r14
jle 0x71f3f
movsd (%rdx), %xmm0
addsd %xmm3, %xmm0
leaq (%rax,%r8), %rsi
addq %rbx, %rcx
addq %r15, %rdx
ucomisd %xmm3, %xmm0
jne 0x71f12
jp 0x71f12
movq $0x0, (%rdi,%rcx,8)
movl %r14d, %ecx
cmpq %r10, %rcx
je 0x72031
sarq $0x20, %rax
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
cmpq %rax, %r9
jle 0x71f86
movl 0x24(%rsp), %esi
movq %r9, %rcx
movslq %esi, %r8
movsd (%rdi,%r8,8), %xmm0
addsd %xmm3, %xmm0
ucomisd %xmm3, %xmm0
jne 0x71f75
jnp 0x71f82
decq %rcx
addl %r13d, %esi
cmpq %rax, %rcx
jg 0x71f60
jmp 0x71f86
decl %ecx
movl %ecx, %edx
testl %edx, %edx
js 0x71fa2
movl %edx, %eax
cmpq %rax, %r10
jne 0x71fe4
xorl %esi, %esi
movq 0x28(%rsp), %rcx
movl %r12d, %r9d
callq 0x7131f
jmp 0x72002
movl %r14d, %esi
movl %r10d, %edx
movq 0x28(%rsp), %rcx
movl %r12d, %r9d
callq 0x718b8
movl 0x18(%rsp), %eax
movl %eax, 0x8(%rsp)
movl %r12d, (%rsp)
movq 0x58(%rsp), %rdi
movl %r14d, %esi
movq 0x60(%rsp), %rdx
movq 0x38(%rsp), %rcx
movq 0x28(%rsp), %r8
movl 0x1c(%rsp), %r9d
callq 0x71501
jmp 0x72002
movl 0x18(%rsp), %eax
movl %eax, (%rsp)
movl %edx, %esi
movl %r10d, %edx
movq 0x38(%rsp), %rcx
movl 0x1c(%rsp), %r8d
movl %r12d, %r9d
callq 0x71149
incl %ebp
cmpl $0x64, %ebp
movq 0x58(%rsp), %rdi
movapd 0x80(%rsp), %xmm3
movabsq $-0x100000000, %r8      # imm = 0xFFFFFFFF00000000
movq 0x60(%rsp), %r10
movq 0x78(%rsp), %r9
jne 0x71f00
jmp 0x7207e
movl 0x20(%rsp), %eax
imull %r12d, %eax
cltq
leaq (%rdi,%r10,8), %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm1
jbe 0x7207e
xorpd 0x2ffca(%rip), %xmm0    # 0xa2020
movlpd %xmm0, (%rcx,%rax,8)
xorl %eax, %eax
movq 0x30(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm0
xorpd 0x2ffb1(%rip), %xmm0    # 0xa2020
movlpd %xmm0, (%rcx,%rax,8)
incq %rax
cmpq %rax, 0x70(%rsp)
jne 0x7205d
addq %r8, 0x50(%rsp)
addq %rbx, 0x48(%rsp)
addq %r15, 0x40(%rsp)
addl %r13d, 0x24(%rsp)
movq 0x30(%rsp), %rax
addq 0x68(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x1, %r9
jg 0x71eea
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq