// File: /workspace/github_c_makefile_star2_O3/sheneman[P]clearcut/clearcut.c
// Function: NJ_collapse
static inline
void
NJ_collapse(DMAT *dmat,
	    NJ_VERTEX *vertex,
	    long int a,
	    long int b) {


  long int i;     /* index used for looping */
  long int size;  /* size of dmat --> reduce pointer dereferencing */
  float a2clade;  /* distance from a to the new node that joins a and b */
  float b2clade;  /* distance from b to the new node that joins a and b */
  float cval;     /* stores distance information during loop */
  float *vptr;    /* pointer to elements in first row of dist matrix */
  float *ptra;    /* pointer to elements in row a of distance matrix */
  float *ptrb;    /* pointer to elements in row b of distance matrix */

  float *val, *r, *r2;  /* simply used to limit pointer dereferencing */


  /* We must assume that a < b */
  if(a >= b) {
    fprintf(stderr, "Clearcut: (a<b) constraint check failed in NJ_collapse()\n");
    exit(0);
  }

  /* some shortcuts to help limit dereferencing */
  val  = dmat->val;
  r    = dmat->r;
  r2   = dmat->r2;
  size = dmat->size;

  /* compute the distance from the clade components (a, b) to the new node */
  a2clade = 
    ( (val[NJ_MAP(a, b, size)]) + (dmat->r2[a] - dmat->r2[b]) ) / 2.0;  
  b2clade = 
    ( (val[NJ_MAP(a, b, size)]) + (dmat->r2[b] - dmat->r2[a]) ) / 2.0;  


  r[a] = 0.0;  /* we are removing row a, so clear dist. in r */

  /* 
   * Fill the horizontal part of the "a" row and finish computing r and r2 
   * we handle the horizontal component first to maximize cache locality
   */
  ptra = &(val[NJ_MAP(a,   a+1, size)]);   /* start ptra at the horiz. of a  */
  ptrb = &(val[NJ_MAP(a+1, b,   size)]);   /* start ptrb at comparable place */
  for(i=a+1;i<size;i++) {

    /* 
     * Compute distance from new internal node to others in 
     * the distance matrix.
     */
    cval = 
      ( (*ptra - a2clade) +
	(*ptrb - b2clade) ) / 2.0;

    /* incr.  row b pointer differently depending on where i is in loop */
    if(i<b) {
      ptrb += size-i-1;  /* traverse vertically  by incrementing by row */
    } else {
      ptrb++;            /* traverse horiz. by incrementing by column   */
    }

    /* assign the newly computed distance and increment a ptr by a column */
    *(ptra++) = cval;  

    /* accumulate the distance onto the r vector */
    r[a] += cval;
    r[i] += cval;
    
    /* scale r2 on the fly here */
    r2[i] = r[i]/(float)(size-3);
  }

  /* fill the vertical part of the "a" column and finish computing r and r2 */ 
  ptra = val + a;  /* start at the top of the columb for "a" */
  ptrb = val + b;  /* start at the top of the columb for "b" */
  for(i=0;i<a;i++) {

    /* 
     * Compute distance from new internal node to others in 
     * the distance matrix.
     */
    cval = 
      ( (*ptra - a2clade) + 
	(*ptrb - b2clade) ) / 2.0;
    
    /* assign the newly computed distance and increment a ptr by a column */
    *ptra = cval;

    /* accumulate the distance onto the r vector */
    r[a] += cval;
    r[i] += cval;

    /* scale r2 on the fly here */
    r2[i] = r[i]/(float)(size-3);

    /* here, always increment by an entire row */
    ptra += size-i-1;
    ptrb += size-i-1;
  }


  /* scale r2 on the fly here */
  r2[a] = r[a]/(float)(size-3);



  /* 
   * Copy row 0 into row b.  Again, the code is structured into two 
   * loops to maximize cache locality for writes along the horizontal
   * component of row b.
   */
  vptr = val;
  ptrb = val + b;
  for(i=0;i<b;i++) {
    *ptrb = *(vptr++);
    ptrb += size-i-1;
  }
  vptr++;  /* skip over the diagonal */
  ptrb = &(val[NJ_MAP(b, b+1, size)]); 
  for(i=b+1;i<size;i++) {
    *(ptrb++) = *(vptr++);
  }

  /* 
   * Collapse r here by copying contents of r[0] into r[b] and
   * incrementing pointer to the beginning of r by one row
   */
  r[b]    = r[0];
  dmat->r = r+1;


  /* 
   * Collapse r2 here by copying contents of r2[0] into r2[b] and
   * incrementing pointer to the beginning of r2 by one row
   */
  r2[b]    = r2[0];
  dmat->r2 = r2+1;

  /* increment dmat pointer to next row */
  dmat->val += size;
  
  /* decrement the total size of the distance matrix by one row */
  dmat->size--;

  return;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
pushq %rax
cmpq %rdx, %rsi
jge 0x43bc
movq 0x8(%rdi), %rax
movq 0x18(%rdi), %rcx
movq 0x28(%rdi), %r9
movq 0x30(%rdi), %r8
movq %rsi, %r10
notq %r10
leaq (%r10,%rax,2), %r10
imulq %rsi, %r10
movq %r10, %r11
shrq $0x3f, %r11
addq %r10, %r11
andq $-0x2, %r11
leaq (%rcx,%r11,2), %r11
movss (%r8,%rdx,4), %xmm0
movss (%r8,%rsi,4), %xmm1
movaps %xmm1, %xmm2
unpcklps %xmm0, %xmm2            # xmm2 = xmm2[0],xmm0[0],xmm2[1],xmm0[1]
unpcklps %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
subps %xmm0, %xmm2
movss (%r11,%rdx,4), %xmm0
shufps $0x0, %xmm0, %xmm0      # xmm0 = xmm0[0,0,0,0]
addps %xmm2, %xmm0
mulps 0x3ed1(%rip), %xmm0     # 0x8060
leaq (%rax,%rax), %r10
movl $0x0, (%r9,%rsi,4)
leaq 0x1(%rsi), %rbx
cmpq %rax, %rbx
jge 0x4256
movq %r10, %r14
subq %rsi, %r14
addq $-0x2, %r14
imulq %rbx, %r14
movq %r14, %r15
shrq $0x3f, %r15
addq %r14, %r15
andq $-0x2, %r15
leaq (%rcx,%r15,2), %r14
leaq (%r14,%rdx,4), %r14
leaq -0x3(%rax), %r15
xorps %xmm1, %xmm1
cvtsi2ss %r15, %xmm1
movq %rax, %r15
subq %rsi, %r15
leaq -0x8(,%r15,4), %r15
movss 0x3e8e(%rip), %xmm2     # 0x807c
movss (%r11,%rbx,4), %xmm3
movss (%r14), %xmm4
unpcklps %xmm4, %xmm3            # xmm3 = xmm3[0],xmm4[0],xmm3[1],xmm4[1]
subps %xmm0, %xmm3
movaps %xmm3, %xmm4
shufps $0x55, %xmm3, %xmm4     # xmm4 = xmm4[1,1],xmm3[1,1]
addss %xmm3, %xmm4
mulss %xmm2, %xmm4
cmpq %rdx, %rbx
movl $0x4, %r12d
cmovlq %r15, %r12
addq %r12, %r14
movss %xmm4, (%r11,%rbx,4)
movss (%r9,%rsi,4), %xmm3
addss %xmm4, %xmm3
movss %xmm3, (%r9,%rsi,4)
addss (%r9,%rbx,4), %xmm4
movss %xmm4, (%r9,%rbx,4)
divss %xmm1, %xmm4
movss %xmm4, (%r8,%rbx,4)
incq %rbx
addq $-0x4, %r15
cmpq %rbx, %rax
jne 0x41ee
leaq (%rcx,%rdx,4), %r11
testq %rsi, %rsi
jle 0x42e3
leaq (%rcx,%rsi,4), %rbx
leaq -0x3(%rax), %r14
xorps %xmm1, %xmm1
cvtsi2ss %r14, %xmm1
leaq -0x1(%rax), %r14
xorl %r15d, %r15d
movss 0x3dfa(%rip), %xmm2     # 0x807c
movq %r11, %r12
movss (%r12), %xmm3
movss (%rbx), %xmm4
unpcklps %xmm3, %xmm4            # xmm4 = xmm4[0],xmm3[0],xmm4[1],xmm3[1]
subps %xmm0, %xmm4
movaps %xmm4, %xmm3
shufps $0x55, %xmm4, %xmm3     # xmm3 = xmm3[1,1],xmm4[1,1]
addss %xmm4, %xmm3
mulss %xmm2, %xmm3
movss %xmm3, (%rbx)
movss (%r9,%rsi,4), %xmm4
addss %xmm3, %xmm4
movss %xmm4, (%r9,%rsi,4)
addss (%r9,%r15,4), %xmm3
movss %xmm3, (%r9,%r15,4)
divss %xmm1, %xmm3
movss %xmm3, (%r8,%r15,4)
leaq (%rbx,%r14,4), %rbx
leaq (%r12,%r14,4), %r12
incq %r15
decq %r14
cmpq %r15, %rsi
jne 0x4285
jmp 0x42ef
leaq -0x3(%rax), %rbx
xorps %xmm1, %xmm1
cvtsi2ss %rbx, %xmm1
movss (%r9,%rsi,4), %xmm0
divss %xmm1, %xmm0
movss %xmm0, (%r8,%rsi,4)
movq %rcx, %rsi
testq %rdx, %rdx
jle 0x432a
leaq -0x1(%rax), %rbx
movq %rdx, %r14
movq %rcx, %rsi
movss (%rsi), %xmm0
addq $0x4, %rsi
movss %xmm0, (%r11)
leaq (%r11,%rbx,4), %r11
decq %rbx
decq %r14
jne 0x4311
leaq 0x1(%rdx), %r11
cmpq %rax, %r11
jge 0x437b
movq %rdx, %r11
notq %r11
addq %r11, %r10
imulq %rdx, %r10
movq %r10, %r11
shrq $0x3f, %r11
addq %r10, %r11
movq %rax, %r10
subq %rdx, %r10
andq $-0x2, %r11
leaq (,%rdx,4), %rbx
leaq (%rbx,%r11,2), %r11
addq %rcx, %r11
movl $0x1, %ebx
movss (%rsi,%rbx,4), %xmm0
movss %xmm0, (%r11,%rbx,4)
incq %rbx
cmpq %rbx, %r10
jne 0x4368
movss (%r9), %xmm0
movss %xmm0, (%r9,%rdx,4)
addq $0x4, %r9
movq %r9, 0x28(%rdi)
movss (%r8), %xmm0
movss %xmm0, (%r8,%rdx,4)
addq $0x4, %r8
movq %r8, 0x30(%rdi)
leaq (%rcx,%rax,4), %rcx
movq %rcx, 0x18(%rdi)
decq %rax
movq %rax, 0x8(%rdi)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
callq 0x2333