/****** generic_staples.c  -- compute the staple ******************/

void staples_MATRIX(MATRIX *link[NDIM], MATRIX *staple, int dir1, int parity) 
{
  register int i,dir2,odir;
  msg_tag *tag0,*tag1,*tag2;
  int start, otherparity;
  MATRIX tmat1,tmat2;
  MATRIX *tmpmat;

  /* get temporary matrix */
  tmpmat  = tmp_latfield( MATRIX );

  /* Loop over other directions, computing force from plaquettes in
     the dir1,dir2 plane */
  
  otherparity = opp_parity(parity);  /* evenodd -> evenodd */

  start=1; /* indicates staple sum not initialized */
  foralldir(dir2) if (dir2 != dir1) {
  
    odir = opp_dir(dir2);

    /* first, get link[dir2] from dir1 to all points */
 
    /* get link[dir2] from direction dir1 */
    tag0 = start_get( link[dir2], dir1, EVENODD );

    /* get link[dir1] from direction dir2 */
    tag1 = start_get( link[dir1], dir2, parity );
    
    /* multiply  link[dir2]^* link[dir1] link[dir2] at direction -dir2 */
    forparity_wait(i, otherparity, tag0) {
      prefetch_MATRIX(&link[dir2][i+1]);
      prefetch_MATRIX(&link[dir1][i+1]);
      prefetch_MATRIX( &link[dir2][nb(dir1,i+1)] );

      mult_MATRIX_an( link[dir2][i], link[dir1][i], tmat1 );
      mult_MATRIX_nn( tmat1, link[dir2][nb(dir1,i)], tmpmat[i] );
    }

    /* bottom staple ready, push up */
    tag2 = start_get( tmpmat, odir, parity );

    wait_get(tag1); 
    /* just try to see what comes ..*/
    if(start){  /* this is the first contribution to staple */
      forparity(i,parity){
	prefetch_MATRIX( &link[dir2][nb(dir1,i)] );
        mult_MATRIX_nn( link[dir2][i], link[dir1][nb(dir2,i)], tmat1 );
	prefetch_MATRIX( &link[dir2][i+1] );
	prefetch_MATRIX( &link[dir1][nb(dir2,i+1)] );
	mult_MATRIX_na( tmat1, link[dir2][nb(dir1,i)], staple[i] );
      }
      start=0;
    } else {
      forparity(i,parity){
	prefetch_MATRIX( &link[dir2][nb(dir1,i)] );
        mult_MATRIX_nn( link[dir2][i], link[dir1][nb(dir2,i)], tmat1 );
	prefetch_MATRIX( &link[dir2][i+1] );
	prefetch_MATRIX( &link[dir1][nb(dir2,i+1)] );
	mult_MATRIX_na( tmat1, link[dir2][nb(dir1,i)], tmat2 );
	add_MATRIX( staple[i], tmat2, staple[i] );
      }
    } /* upper staple */

    /* Lower staple */
    wait_get(tag2);
    forparity(i,parity){
      prefetch_MATRIX( &staple[i+1] );
      prefetch_MATRIX( &tmpmat[nb(odir,i+1)]);
      add_MATRIX( staple[i], tmpmat[nb(odir,i)], staple[i] );
    }  /* lower staple */
  }
  free_tmp( tmpmat );
}

