// File: tomfunkhouser[P]gaps/pkgs/RNBasics/RNSvd.cpp
// Function: gaps::golub_kahn_svd_rot(double*, int, int, double*, int, int, int)
void golub_kahn_svd_rot(RNScalar * b,int p,int q,RNScalar * v,int m,int n,int min)
{
    RNScalar t11, t12, t22;
    RNScalar uu;
    RNScalar b11, b12;
    RNScalar dm,fm,dn,fn;
    RNScalar hypot,cos,sin;
    RNScalar d, s, y, z;

    /* grab the last diagonal and superdiagonal elements of b22 */
    fm = (q-2) < 0 ? 0 : REF2D(b,m,n,q-2,q-1);
    dm = REF2D(b,m,n,q-1,q-1);	fn = REF2D(b,m,n,q-1,q);
				dn = REF2D(b,m,n,q,q);

    /* create the trailing 2x2 submatrix of T = b22^t b22 */
    t11 = dm*dm + fm * fm;
    t12 = dm * fn;		t22 = dn * dn + fn * fn;

    /* find the eigenvalues of the T matrix.
    **
    ** The quadratic equation for the eigenvalues has coefficients:
    ** a = 1
    ** b = -(t11+t22)
    ** c = t11 t22 - t12 t12
    **
    ** b^2 - 4ac = (t11^2 + t22^2 + 2 t11 t12) - 4 t11 t22 + 4 t12 t12
    **           = (t11 - t22)^2 + 4 t12 t12
    **
    ** sqrt(b^2-4ac) = sqrt((t11 - t22)^2 + 4 t12 t12) -- use "pythag()"
    **
    ** using quadratic formula, we have the eigenvalues:
    ** (u1,u2) = .5 (t11 + t22 +/- pythag(...))
    **         = t22 + .5 (t11 - t22 +/- pythag(...))
    **
    ** We propogate the .5 into the pythag term, yielding golub's equation 8.2-2
    ** for the "wilkinson shift".
    ** [Note:  Golub says to use (t22 + d - signum(d) s) to find the eigenvalue
    ** closer to t22.  He's right.  ]
    **/
    d = ((RNScalar) 0.5)*(t11 - t22);
    s = fhypot (d,t12);
    uu = t22 + d + ((d > 0) ? -s : s);

    /* grab the leading 2x1 of b */
    b11 = REF2D(b,m,n,p,p);	b12 = REF2D(b,m,n,p,p+1);

    /* make the leading 2x1 submatrix of T */
    t11 = b11 * b11;
    t12 = b11 * b12;

    /* calculate the rotation that would zero the off-diagonal term of the
    ** shifted matrix T - uu I
    */
    y = t11 - uu;
    z = t12;
    hypot = fhypot (y,z);
    cos = y / hypot;
    sin = z / hypot;

    /* perform the rotation on B.  This sprays some glop into the upper-left
    ** subdiagonal element.
    */
    rotate_cols(p,p+1,cos,sin,b,p,2,m,n);
    /* accumulate the rotation into the rows of v */
    rotate_rows(p,p+1,cos,sin,v,0,n,min,n);
}

// Assembly:
subq $0xc8, %rsp
movl 0xd0(%rsp), %eax
movq %rdi, 0xc0(%rsp)
movl %esi, 0xbc(%rsp)
movl %edx, 0xb8(%rsp)
movq %rcx, 0xb0(%rsp)
movl %r8d, 0xac(%rsp)
movl %r9d, 0xa8(%rsp)
movl 0xb8(%rsp), %eax
subl $0x2, %eax
cmpl $0x0, %eax
jge 0xd3346
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
jmp 0xd337c
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
movl 0xb8(%rsp), %edx
subl $0x2, %edx
imull %edx, %ecx
movl 0xb8(%rsp), %edx
subl $0x1, %edx
addl %edx, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x68(%rsp)
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
movl 0xb8(%rsp), %edx
subl $0x1, %edx
imull %edx, %ecx
movl 0xb8(%rsp), %edx
subl $0x1, %edx
addl %edx, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x70(%rsp)
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
movl 0xb8(%rsp), %edx
subl $0x1, %edx
imull %edx, %ecx
addl 0xb8(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x58(%rsp)
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
imull 0xb8(%rsp), %ecx
addl 0xb8(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0x70(%rsp), %xmm0
movsd 0x70(%rsp), %xmm2
movsd 0x68(%rsp), %xmm1
mulsd 0x68(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xa0(%rsp)
movsd 0x70(%rsp), %xmm0
mulsd 0x58(%rsp), %xmm0
movsd %xmm0, 0x98(%rsp)
movsd 0x60(%rsp), %xmm0
movsd 0x60(%rsp), %xmm2
movsd 0x58(%rsp), %xmm1
mulsd 0x58(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x90(%rsp)
movsd 0xa0(%rsp), %xmm1
subsd 0x90(%rsp), %xmm1
movsd 0x5fb74(%rip), %xmm0    # 0x133010
mulsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movsd 0x38(%rsp), %xmm0
movsd 0x98(%rsp), %xmm1
callq 0xd2140
movsd %xmm0, 0x30(%rsp)
movsd 0x90(%rsp), %xmm0
addsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x38(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0xd3509
movsd 0x30(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, 0x8(%rsp)
jmp 0xd3515
movsd 0x30(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x10(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, 0x88(%rsp)
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
imull 0xbc(%rsp), %ecx
addl 0xbc(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x80(%rsp)
movq 0xc0(%rsp), %rax
movl 0xa8(%rsp), %ecx
imull 0xbc(%rsp), %ecx
movl 0xbc(%rsp), %edx
addl $0x1, %edx
addl %edx, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x80(%rsp), %xmm0
mulsd 0x80(%rsp), %xmm0
movsd %xmm0, 0xa0(%rsp)
movsd 0x80(%rsp), %xmm0
mulsd 0x78(%rsp), %xmm0
movsd %xmm0, 0x98(%rsp)
movsd 0xa0(%rsp), %xmm0
subsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
movsd 0x98(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x28(%rsp), %xmm0
movsd 0x20(%rsp), %xmm1
callq 0xd2140
movsd %xmm0, 0x50(%rsp)
movsd 0x28(%rsp), %xmm0
divsd 0x50(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movsd 0x20(%rsp), %xmm0
divsd 0x50(%rsp), %xmm0
movsd %xmm0, 0x40(%rsp)
movl 0xbc(%rsp), %edi
movl 0xbc(%rsp), %esi
addl $0x1, %esi
movsd 0x48(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
movq 0xc0(%rsp), %rdx
movl 0xbc(%rsp), %ecx
movl 0xac(%rsp), %r9d
movl 0xa8(%rsp), %eax
movl $0x2, %r8d
movl %eax, (%rsp)
callq 0xd2a40
movl 0xbc(%rsp), %edi
movl 0xbc(%rsp), %esi
addl $0x1, %esi
movsd 0x48(%rsp), %xmm0
movsd 0x40(%rsp), %xmm1
movq 0xb0(%rsp), %rdx
movl 0xa8(%rsp), %r8d
movl 0xd0(%rsp), %r9d
movl 0xa8(%rsp), %eax
xorl %ecx, %ecx
movl %eax, (%rsp)
callq 0xd2b70
addq $0xc8, %rsp
retq
nopw (%rax,%rax)