/*
     -- micMAGMA (version 0.1) --
        Univ. of Tennessee, Knoxville
        Univ. of California, Berkeley
        Univ. of Colorado, Denver

        April 2012

        @authors Azzam Haidar
        @authors Yulu Jia
        @authors Stan Tomov

        @precisions normal z -> s d c

*/

#include <stdio.h>
#include "common_magma.h"

#define PRECISION_z
//#define ENABLE_TIMER

magma_err_t
magma_zlabrd_mic( magma_int_t m, magma_int_t n, magma_int_t nb,
                  magmaDoubleComplex *a, magma_int_t lda,
                  magmaDoubleComplex_ptr da, size_t da_offset, magma_int_t ldda,
                  double *d, double *e, magmaDoubleComplex *tauq, magmaDoubleComplex *taup,
                  magmaDoubleComplex *x, magma_int_t ldx,
                  magmaDoubleComplex_ptr dx, size_t dx_offset, magma_int_t lddx,
                  magmaDoubleComplex *y, magma_int_t ldy,
                  magmaDoubleComplex_ptr dy, size_t dy_offset, magma_int_t lddy,
                  magma_queue_t queue )
{
/*  -- MAGMA (version 1.1) --
       Univ. of Tennessee, Knoxville
       Univ. of California, Berkeley
       Univ. of Colorado, Denver
       November 2011

    Purpose
    =======
    ZLABRD reduces the first NB rows and columns of a complex general
    m by n matrix A to upper or lower bidiagonal form by an orthogonal
    transformation Q' * A * P, and returns the matrices X and Y which
    are needed to apply the transformation to the unreduced part of A.

    If m >= n, A is reduced to upper bidiagonal form; if m < n, to lower
    bidiagonal form.

    This is an auxiliary routine called by SGEBRD

    Arguments
    =========
    M       (input) INTEGER
            The number of rows in the matrix A.

    N       (input) INTEGER
            The number of columns in the matrix A.

    NB      (input) INTEGER
            The number of leading rows and columns of A to be reduced.

    A       (input/output) COMPLEX_16 array, dimension (LDA,N)
            On entry, the m by n general matrix to be reduced.
            On exit, the first NB rows and columns of the matrix are
            overwritten; the rest of the array is unchanged.
            If m >= n, elements on and below the diagonal in the first NB
              columns, with the array TAUQ, represent the orthogonal
              matrix Q as a product of elementary reflectors; and
              elements above the diagonal in the first NB rows, with the
              array TAUP, represent the orthogonal matrix P as a product
              of elementary reflectors.
            If m < n, elements below the diagonal in the first NB
              columns, with the array TAUQ, represent the orthogonal
              matrix Q as a product of elementary reflectors, and
              elements on and above the diagonal in the first NB rows,
              with the array TAUP, represent the orthogonal matrix P as
              a product of elementary reflectors.
            See Further Details.

    LDA     (input) INTEGER
            The leading dimension of the array A.  LDA >= max(1,M).

    D       (output) COMPLEX_16 array, dimension (NB)
            The diagonal elements of the first NB rows and columns of
            the reduced matrix.  D(i) = A(i,i).

    E       (output) COMPLEX_16 array, dimension (NB)
            The off-diagonal elements of the first NB rows and columns of
            the reduced matrix.

    TAUQ    (output) COMPLEX_16 array dimension (NB)
            The scalar factors of the elementary reflectors which
            represent the orthogonal matrix Q. See Further Details.

    TAUP    (output) COMPLEX_16 array, dimension (NB)
            The scalar factors of the elementary reflectors which
            represent the orthogonal matrix P. See Further Details.

    X       (output) COMPLEX_16 array, dimension (LDX,NB)
            The m-by-nb matrix X required to update the unreduced part
            of A.

    LDX     (input) INTEGER
            The leading dimension of the array X. LDX >= M.

    Y       (output) COMPLEX_16 array, dimension (LDY,NB)
            The n-by-nb matrix Y required to update the unreduced part
            of A.

    LDY     (input) INTEGER
            The leading dimension of the array Y. LDY >= N.

    Further Details
    ===============

    The matrices Q and P are represented as products of elementary
    reflectors:

       Q = H(1) H(2) . . . H(nb)  and  P = G(1) G(2) . . . G(nb)

    Each H(i) and G(i) has the form:

       H(i) = I - tauq * v * v'  and G(i) = I - taup * u * u'

    where tauq and taup are complex scalars, and v and u are complex vectors.

    If m >= n, v(1:i-1) = 0, v(i) = 1, and v(i:m) is stored on exit in
    A(i:m,i); u(1:i) = 0, u(i+1) = 1, and u(i+1:n) is stored on exit in
    A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i).

    If m < n, v(1:i) = 0, v(i+1) = 1, and v(i+1:m) is stored on exit in
    A(i+2:m,i); u(1:i-1) = 0, u(i) = 1, and u(i:n) is stored on exit in
    A(i,i+1:n); tauq is stored in TAUQ(i) and taup in TAUP(i).

    The elements of the vectors v and u together form the m-by-nb matrix
    V and the nb-by-n matrix U' which are needed, with X and Y, to apply
    the transformation to the unreduced part of the matrix, using a block
    update of the form:  A := A - V*Y' - X*U'.

    The contents of A on exit are illustrated by the following examples
    with nb = 2:

    m = 6 and n = 5 (m > n):          m = 5 and n = 6 (m < n):

      (  1   1   u1  u1  u1 )           (  1   u1  u1  u1  u1  u1 )
      (  v1  1   1   u2  u2 )           (  1   1   u2  u2  u2  u2 )
      (  v1  v2  a   a   a  )           (  v1  1   a   a   a   a  )
      (  v1  v2  a   a   a  )           (  v1  v2  a   a   a   a  )
      (  v1  v2  a   a   a  )           (  v1  v2  a   a   a   a  )
      (  v1  v2  a   a   a  )

    where a denotes an element of the original matrix which is unchanged,
    vi denotes an element of the vector defining H(i), and ui an element
    of the vector defining G(i).
    =====================================================================    */
    #if defined (ENABLE_TIMER)
    double tctm1=0., tmtc1=0., tgmv1=0., tctm2=0., tmtc2=0., tgmv2=0.;
    double start, end, tfin, tmag;
    #endif 

    magmaDoubleComplex c_neg_one = MAGMA_Z_NEG_ONE;
    magmaDoubleComplex c_one = MAGMA_Z_ONE;
    magmaDoubleComplex c_zero = MAGMA_Z_ZERO;
    magma_int_t c__1  = 1;
    magma_int_t gmvshift = 0, mgmvblk=240, dmatoffset;
    
    magma_int_t a_dim1, a_offset, x_dim1, x_offset, y_dim1, y_offset, i__2, i__3;
    magma_int_t i__;
    magmaDoubleComplex alpha;

    a_dim1 = lda;
    a_offset = 1 + a_dim1;
    a -= a_offset;
    --d;
    --e;
    --tauq;
    --taup;

    x_dim1 = ldx;
    x_offset = 1 + x_dim1;
    x -= x_offset;
    //dx_offset -= 1 + lddx;

    y_dim1 = ldy;
    y_offset = 1 + y_dim1;
    y -= y_offset;
    //dy_offset -= 1 + lddy;

    if (m <= 0 || n <= 0) {
        return 0;
    }

    #if defined (ENABLE_TIMER)
    tfin = magma_wtime();
    #endif

    magma_event_t event = NULL;

    magmaDoubleComplex *cpuw  = NULL;
    magmaDoubleComplex *cpuw1 = NULL;
    magmaDoubleComplex *cpuw2 = NULL;    
    magmaDoubleComplex *dtmp  = NULL;    

    if (MAGMA_SUCCESS != magma_zmalloc( &dtmp, max(m,n) )) {
        return  MAGMA_ERR_DEVICE_ALLOC;
    }
    if (MAGMA_SUCCESS != magma_zmalloc_pinned( &cpuw, 2*max(m,n) )) {
        return  MAGMA_ERR_HOST_ALLOC;
    }
    cpuw1 = cpuw;
    cpuw2 = cpuw + max(m,n); 

    #if defined (ENABLE_TIMER)
    tmag = magma_wtime();
    #endif

    if (m >= n) {
            /* Reduce to upper bidiagonal form */
            for (i__ = 1; i__ <= nb; ++i__) {

                    /*  Update A(i:m,i) */
                    i__2 = m - i__ + 1;
                    i__3 = i__ - 1;
                    #if defined(PRECISION_z) || defined(PRECISION_c)
                    lapackf77_zlacgv( &i__3, &y[i__+y_dim1], &ldy );
                    #endif
                    blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one, &a[i__ + a_dim1], &lda,
                                    &y[i__+y_dim1], &ldy, &c_one, &a[i__ + i__ * a_dim1], &c__1);
                    #if defined(PRECISION_z) || defined(PRECISION_c)
                    lapackf77_zlacgv( &i__3, &y[i__+y_dim1], &ldy );
                    #endif
                    blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one, &x[i__ + x_dim1], &ldx,
                                    &a[i__*a_dim1+1], &c__1, &c_one, &a[i__+i__*a_dim1], &c__1);
            
                    /* Generate reflection Q(i) to annihilate A(i+1:m,i) */
                    alpha = a[i__ + i__ * a_dim1];
                    i__2 = m - i__ + 1;
                    i__3 = i__ + 1;
                    lapackf77_zlarfg(&i__2, &alpha,
                                    &a[min(i__3,m) + i__ * a_dim1], &c__1, &tauq[i__]);
                    d[i__] = MAGMA_Z_REAL( alpha );
                    if (i__ < n) {
                            a[i__ + i__ * a_dim1] = c_one;
                            /* Compute Y(i+1:n,i) */
                            i__2 = m - i__ + 1;
                            i__3 = n - i__;

                            #if defined (ENABLE_TIMER)
                            start = magma_wtime();
                            #endif 
                            // 1. Send the block reflector  A(i+1:m,i) to the MIC ------
                            /*
                            magma_zsetmatrix( i__2, 1,
                                            a + i__   + i__   * a_dim1, 0, lda,
                                            da, da_offset + (i__-1)+(i__-1)* (ldda), ldda,
                                            queue );
                            */
                            magma_zsetmatrix_async( i__2, 1,
                                              a + i__   + i__   * a_dim1, 0, lda,
                                              da, da_offset + (i__-1)+(i__-1)* (ldda), ldda,
                                              queue, &event );
                            magma_event_sync( event );
                            #if defined (ENABLE_TIMER)
                            magma_kernel_sync();
                            end = magma_wtime() - start;
                            tctm1 = tctm1+end;
                            #endif
                            // 2. Multiply ---------------------------------------------
                            #if defined (ENABLE_TIMER)
                            start = magma_wtime();
                            #endif 
			    // gmvshift is a shift to allow better performance of the gemv of MIc.
			    // the day MKL optimize their gemv to be always at high perf we can put it to 0
                            // for transpose shift col
                            /*
                            gmvshift = 0;
                            magma_zgemv(MagmaConjTrans, i__2, i__3, c_one,
                                        da, da_offset + (i__-1) + ((i__-1) + 1) * (ldda), ldda,
                                        da, da_offset + (i__-1) + (i__-1) * (ldda), c__1, c_zero,
                                        dy, dy_offset , c__1,
                                        queue );
                            */
                            gmvshift = i__ - ((i__/mgmvblk)*mgmvblk) ;
                            dmatoffset = da_offset + (i__-1) + ((i__-1) + 1 - gmvshift) * (ldda) ;
                            magma_zgemv(MagmaConjTrans, i__2, i__3+gmvshift, c_one,
                                        da, dmatoffset, ldda,
                                        da, da_offset + (i__-1) + (i__-1) * (ldda), c__1, c_zero,
                                        dy, dy_offset , c__1,
                                        queue );
                            #if defined (ENABLE_TIMER)
                            magma_kernel_sync();
                            end = magma_wtime() - start;
                            tgmv1 = tgmv1+end;
                            #endif
                            // 3. Put the result back ----------------------------------
                            #if defined (ENABLE_TIMER)
                            start = magma_wtime();
                            #endif
			    /*
			    magma_zgetmatrix( i__3, 1,
					    dy, dy_offset+gmvshift, y_dim1,
					    y+i__+1+i__*y_dim1, 0, y_dim1,
					    queue);
                            */
                            magma_kernel_sync();
                            magma_zgetmatrix_async( i__3, 1,
                                                    dy, dy_offset+gmvshift, y_dim1,
                                                    y+i__+1+i__*y_dim1, 0, y_dim1,
                                                    queue, &event );
                            #if defined (ENABLE_TIMER)
                            magma_kernel_sync();
                            end = magma_wtime() - start;
                            tmtc1 = tmtc1+end;
                            #endif
                            i__2 = m - i__ + 1;
                            i__3 = i__ - 1;
                            blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_one, &a[i__ + a_dim1],
                                          &lda, &a[i__ + i__ * a_dim1], &c__1, &c_zero,
                                          &y[i__ * y_dim1 + 1], &c__1);
                           
                            i__2 = n - i__;
                            i__3 = i__ - 1;
                            blasf77_zgemv("N", &i__2, &i__3, &c_neg_one, &y[i__ + 1 +y_dim1], &ldy,
                                          &y[i__ * y_dim1 + 1], &c__1,
                                          &c_zero, cpuw1, &c__1);
                            i__2 = m - i__ + 1;
                            i__3 = i__ - 1;
                            blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_one, &x[i__ + x_dim1],
                                  &ldx, &a[i__ + i__ * a_dim1], &c__1, &c_zero,
                                  &y[i__ * y_dim1 + 1], &c__1);
                           // 4. Synch to make sure the result is back ----------------
                           magma_event_sync( event );
                          
                           if (i__3!=0){
                             i__2 = n - i__;
                             blasf77_zaxpy(&i__2, &c_one, cpuw1,&c__1, &y[i__+1+i__*y_dim1],&c__1);
                           }
                          
                           i__2 = i__ - 1;
                           i__3 = n - i__;
                           blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_neg_one,
                                         &a[(i__ + 1) * a_dim1 + 1], &lda, &y[i__ * y_dim1 + 1], &c__1, &c_one,
                                         &y[i__ + 1 + i__ * y_dim1], &c__1);
                           i__2 = n - i__;
                           blasf77_zscal(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1);
                          
                           /* Update A(i,i+1:n) */
                           i__2 = n - i__;
                           #if defined(PRECISION_z) || defined(PRECISION_c)
                           lapackf77_zlacgv( &i__2, &a[i__+(i__+1)*a_dim1], &lda );
                           lapackf77_zlacgv( &i__,  &a[i__+a_dim1], &lda );
                           #endif
                           blasf77_zgemv("No transpose", &i__2, &i__, &c_neg_one,
                                         &y[i__ + 1 + y_dim1], &ldy, &a[i__ + a_dim1], &lda,
                                         &c_one, &a[i__ + (i__ + 1) * a_dim1], &lda);
                           i__2 = i__ - 1;
                           i__3 = n - i__;
                           #if defined(PRECISION_z) || defined(PRECISION_c)
                           lapackf77_zlacgv( &i__,  &a[i__+a_dim1], &lda );
                           lapackf77_zlacgv( &i__2, &x[i__+x_dim1], &ldx );
                           #endif
                           blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_neg_one, &a[(i__ + 1) *
                                   a_dim1 + 1], &lda, &x[i__ + x_dim1], &ldx, &c_one, &a[
                                   i__ + (i__ + 1) * a_dim1], &lda);
                           #if defined(PRECISION_z) || defined(PRECISION_c)
                           lapackf77_zlacgv( &i__2, &x[i__+x_dim1], &ldx );
                           #endif
                          
                           /* Generate reflection P(i) to annihilate A(i,i+2:n) */
                           i__2 = n - i__;
                           /* Computing MIN */
                           i__3 = i__ + 2;
                           alpha = a[i__ + (i__ + 1) * a_dim1];
                           lapackf77_zlarfg(&i__2, &alpha, &a[i__ + min(
                                   i__3,n) * a_dim1], &lda, &taup[i__]);
                           e[i__] = MAGMA_Z_REAL( alpha );
                           a[i__ + (i__ + 1) * a_dim1] = c_one;
                          
                           /* Compute X(i+1:m,i) */
                           i__2 = m - i__;
                           i__3 = n - i__;
                           // 1. Send the block reflector  A(i+1:m,i) to the GPU ------
                           #if defined (ENABLE_TIMER)
                           start = magma_wtime();
                           #endif
                           /*
                           magma_zsetmatrix( 1, i__3,
                                             a + i__   + (i__   +1)* a_dim1, 0, lda,
                                             da, da_offset + (i__-1)+((i__-1)+1)*(ldda), ldda,
                                             queue );
                           */
			   // transpose the row to be a column to be able to use 1 offload call
                           blasf77_zcopy(&i__3, a + i__   + (i__   +1)* a_dim1, &lda, cpuw2, &c__1);
                           //magma_zsetmatrix( i__3, 1, cpuw2, 0, 1, dtmp, 0 , 1, queue );
                           magma_zsetmatrix_async( i__3, 1, cpuw2, 0, 1, dtmp, 0 , 1, queue, &event);
                           magma_event_sync( event );
			   // On the MIC side transpose dtmp to be able to store it on a row of da
                           magma_zcopy(i__3, dtmp, 0, 1, da, da_offset +(i__-1)+((i__-1)+1)*(ldda), ldda, queue);
                           #if defined (ENABLE_TIMER)
                           magma_kernel_sync();
                           end = magma_wtime() - start;
                           tctm2 = tctm2+end;
                           #endif
                           // 2. Multiply ---------------------------------------------
                           #if defined (ENABLE_TIMER)
                           start = magma_wtime();
                           #endif
                           /*
                           gmvshift = 0;
                           magma_zgemv(MagmaNoTrans, i__2, i__3, c_one,
                                       da, da_offset + (i__-1)+1+ ((i__-1)+1) * (ldda), ldda,
                                       //da, da_offset + (i__-1) +  ((i__-1)+1) * (ldda), ldda,
                                       dtmp, 0, 1,
                                       c_zero, dx, dx_offset , c__1,
                                       queue );
                           */
                           // for Non transpose shift row
                           gmvshift = i__ - ((i__/mgmvblk)*mgmvblk) ;
                           //gmvshift = i__ - ((i__/8)*8) ;
                           dmatoffset = da_offset + (i__-1)+1+ ((i__-1)+1) * (ldda) - gmvshift;
                           magma_zgemv(MagmaNoTrans, i__2+gmvshift, i__3, c_one,
                                       da, dmatoffset, ldda,
                                       dtmp, 0, 1,
                                       c_zero, dx, dx_offset , c__1,
                                       queue );
                           #if defined (ENABLE_TIMER)
                           magma_kernel_sync();
                           end = magma_wtime() - start;
                           tgmv2 = tgmv2+end;
                           #endif
                          
                           // 3. Put the result back ----------------------------------
                           #if defined (ENABLE_TIMER)
                           start = magma_wtime();
                           #endif
			   /*
			   magma_zgetmatrix( i__2, 1,
					    dx, dx_offset + gmvshif, x_dim1,
					    x+i__+1+i__*x_dim1, 0, x_dim1,
					    queue);
                           */
                           magma_kernel_sync();
                           magma_zgetmatrix_async( i__2, 1,
                                                   dx, dx_offset + gmvshift , x_dim1,
                                                   x+i__+1+i__*x_dim1, 0, x_dim1,
                                                   queue, &event );
                          
                           #if defined (ENABLE_TIMER)
                           magma_kernel_sync();
                           end = magma_wtime() - start;
                           tmtc2 = tmtc2+end;
                           #endif
                           i__2 = n - i__;
                           blasf77_zgemv(MagmaConjTransStr, &i__2, &i__, &c_one, &y[i__ + 1 + y_dim1],
                                   &ldy, &a[i__ + (i__ + 1) * a_dim1], &lda, &c_zero, &x[
                                   i__ * x_dim1 + 1], &c__1);
                          
                           i__2 = m - i__;
                           blasf77_zgemv("N", &i__2, &i__, &c_neg_one, &a[i__ + 1 + a_dim1], &lda,
                                  &x[i__ * x_dim1 + 1], &c__1, &c_zero, cpuw1, &c__1);
                           i__2 = i__ - 1;
                           i__3 = n - i__;
                           blasf77_zgemv("N", &i__2, &i__3, &c_one, &a[(i__ + 1) * a_dim1 + 1],
                                  &lda, &a[i__ + (i__ + 1) * a_dim1], &lda,
                                  &c_zero, &x[i__ * x_dim1 + 1], &c__1);
                          
                           // 4. Synch to make sure the result is back ----------------
                           magma_event_sync( event );
                          
                           if (i__!=0){
                             i__2 = m - i__;
                             blasf77_zaxpy(&i__2, &c_one, cpuw1,&c__1, &x[i__+1+i__*x_dim1],&c__1);
                           }
                          
                          
                           i__2 = m - i__;
                           i__3 = i__ - 1;
                           blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one, &x[i__ + 1 +
                                   x_dim1], &ldx, &x[i__ * x_dim1 + 1], &c__1, &c_one, &x[
                                   i__ + 1 + i__ * x_dim1], &c__1);
                           i__2 = m - i__;
                           blasf77_zscal(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1);
                           #if defined(PRECISION_z) || defined(PRECISION_c)
                           i__2 = n - i__;
                           lapackf77_zlacgv( &i__2,  &a[i__+(i__+1)*a_dim1], &lda );
                           // 4. Send the block reflector  A(i+1:m,i) to the GPU after ZLACGV()
                           magma_zsetmatrix( 1, i__2, 
                                             a + i__   + (i__   +1)* a_dim1, 0, lda,
                                             da, da_offset + (i__-1)+((i__-1)+1)*(ldda), ldda,
                                             queue );
                           #endif

                    }
            }
    } else {

            /* Reduce to lower bidiagonal form */
            for (i__ = 1; i__ <= nb; ++i__) {

                    /* Update A(i,i:n) */
                    i__2 = n - i__ + 1;
                    i__3 = i__ - 1;
                    #if defined(PRECISION_z) || defined(PRECISION_c)
                    lapackf77_zlacgv(&i__2, &a[i__ + i__ * a_dim1], &lda);
                    lapackf77_zlacgv(&i__3, &a[i__ + a_dim1], &lda);
                    #endif
                    blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one, &y[i__ + y_dim1], &ldy,
                                    &a[i__ + a_dim1], &lda, &c_one, &a[i__ + i__ * a_dim1], &lda);
                    i__2 = i__ - 1;
                    #if defined(PRECISION_z) || defined(PRECISION_c)
                    lapackf77_zlacgv(&i__3, &a[i__ + a_dim1], &lda);
                    lapackf77_zlacgv(&i__3, &x[i__ + x_dim1], &ldx);
                    #endif
                    i__3 = n - i__ + 1;
                    blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_neg_one, &a[i__ * a_dim1 + 1],
                                    &lda, &x[i__ + x_dim1], &ldx, &c_one, &a[i__ + i__ * a_dim1], &lda);
                    #if defined(PRECISION_z) || defined(PRECISION_c)
                    lapackf77_zlacgv(&i__2, &x[i__ + x_dim1], &ldx);
                    #endif

                    /* Generate reflection P(i) to annihilate A(i,i+1:n) */
                    i__2 = n - i__ + 1;
                    /* Computing MIN */
                    i__3 = i__ + 1;
                    alpha = a[i__ + i__ * a_dim1];
                    lapackf77_zlarfg(&i__2, &alpha,
                                    &a[i__ + min(i__3,n) * a_dim1], &lda, &taup[i__]);
                    d[i__] = MAGMA_Z_REAL( alpha );
                    if (i__ < m) {
                            a[i__ + i__ * a_dim1] = c_one;

                            /* Compute X(i+1:m,i) */
                            i__2 = m - i__;
                            i__3 = n - i__ + 1;

                            // 1. Send the block reflector  A(i,i+1:n) to the MIC ------
			    /*
                            magma_zsetmatrix( 1, i__3,
                                            a + i__   + i__   * a_dim1, 0, lda,
                                            da, da_offset + (i__-1)+(i__-1)* (ldda), ldda,
                                            queue );
                            // 2. Multiply ---------------------------------------------
                            magma_zgemv(MagmaNoTrans, i__2, i__3, c_one,
                                            da, da_offset + (i__-1)+1 + (i__-1) * ldda, ldda,
                                            da, da_offset + (i__-1)   + (i__-1) * ldda, ldda,
                                            c_zero,
                                            dx, dx_offset, c__1,
                                            queue );
			   
			    */
			    // transpose the row to be a column to be able to use 1 offload call
                            blasf77_zcopy(&i__3, a + i__   + i__   * a_dim1, &lda, cpuw2, &c__1);
                            //magma_zsetmatrix( i__3, 1, cpuw2, 0, 1, dtmp, 0 , 1, queue );
                            magma_zsetmatrix_async( i__3, 1, cpuw2, 0, 1, dtmp, 0 , 1, queue, &event);
                            magma_event_sync( event );
			    // On the MIC side transpose dtmp to be able to store it on a row of da
                            magma_zcopy(i__3, dtmp, 0, 1, da, da_offset + (i__-1)   + (i__-1) * ldda, ldda, queue);
                            // 2. Multiply ---------------------------------------------
                            magma_zgemv(MagmaNoTrans, i__2, i__3, c_one,
                                            da, da_offset + (i__-1)+1 + (i__-1) * ldda, ldda,
                                            dtmp, 0, 1,
                                            c_zero,
                                            dx, dx_offset, c__1,
                                            queue );
                            
                            // 3. Put the result back ----------------------------------
                            magma_zgetmatrix( i__2, 1,
                                            dx, dx_offset, x_dim1,
                                            x+i__+1+i__*x_dim1, 0, x_dim1,
                                            queue );

                            i__2 = n - i__ + 1;
                            i__3 = i__ - 1;
                            blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_one, &y[i__ + y_dim1],
                                            &ldy, &a[i__ + i__ * a_dim1], &lda, &c_zero,
                                            &x[i__ *  x_dim1 + 1], &c__1);
                            i__2 = m - i__;
                            i__3 = i__ - 1;
                            blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one,
                                            &a[i__ + 1 + a_dim1], &lda, &x[i__ * x_dim1 + 1], &c__1, &c_zero,
                                            cpuw1, &c__1);

                            i__2 = i__ - 1;
                            i__3 = n - i__ + 1;
                            blasf77_zgemv("No transpose", &i__2, &i__3, &c_one,
                                            &a[i__ * a_dim1 + 1], &lda, &a[i__ + i__ * a_dim1], &lda, &c_zero,
                                            &x[i__ * x_dim1 + 1], &c__1);

                            // 4. Synch to make sure the result is back ----------------
                            //magma_event_sync( event );
                            if (i__2!=0){
                                    i__3 = m - i__;
                                    blasf77_zaxpy(&i__3, &c_one, cpuw1,&c__1, &x[i__+1+i__*x_dim1],&c__1);
                            }

                            i__2 = m - i__;
                            i__3 = i__ - 1;
                            blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one,
                                            &x[i__ + 1 + x_dim1], &ldx, &x[i__ * x_dim1 + 1], &c__1, &c_one,
                                            &x[i__ + 1 + i__ * x_dim1], &c__1);
                            i__2 = m - i__;
                            blasf77_zscal(&i__2, &taup[i__], &x[i__ + 1 + i__ * x_dim1], &c__1);
                            i__2 = n - i__ + 1;
                            #if defined(PRECISION_z) || defined(PRECISION_c)
                            lapackf77_zlacgv(&i__2, &a[i__ + i__ * a_dim1], &lda);
                            magma_zsetmatrix( i__2, 1,
                                            a + i__   + (i__  )* a_dim1, 0, lda,
                                            da, da_offset + (i__-1)+ (i__-1)*(ldda), ldda,
                                            queue );
                            #endif

                            /* Update A(i+1:m,i) */
                            i__2 = m - i__;
                            i__3 = i__ - 1;
                            #if defined(PRECISION_z) || defined(PRECISION_c)
                            lapackf77_zlacgv(&i__3, &y[i__ + y_dim1], &ldy);
                            #endif
                            blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one,
                                            &a[i__ + 1 + a_dim1], &lda, &y[i__ + y_dim1], &ldy, &c_one,
                                            &a[i__ + 1 + i__ * a_dim1], &c__1);
                            i__2 = m - i__;
                            #if defined(PRECISION_z) || defined(PRECISION_c)
                            lapackf77_zlacgv(&i__3, &y[i__ + y_dim1], &ldy);
                            #endif
                            blasf77_zgemv("No transpose", &i__2, &i__, &c_neg_one,
                                            &x[i__ + 1 + x_dim1], &ldx, &a[i__ * a_dim1 + 1], &c__1, &c_one,
                                            &a[i__ + 1 + i__ * a_dim1], &c__1);

                            /* Generate reflection Q(i) to annihilate A(i+2:m,i) */
                            i__2 = m - i__;
                            i__3 = i__ + 2;
                            alpha = a[i__ + 1 + i__ * a_dim1];
                            lapackf77_zlarfg(&i__2, &alpha,
                                            &a[min(i__3,m) + i__ * a_dim1], &c__1, &tauq[i__]);
                            e[i__] = MAGMA_Z_REAL( alpha );
                            a[i__ + 1 + i__ * a_dim1] = c_one;

                            /* Compute Y(i+1:n,i) */
                            i__2 = m - i__;
                            i__3 = n - i__;

                            // 1. Send the block reflector  A(i+1:m,i) to the MIC ------
                            magma_zsetmatrix( i__2, 1,
                                              a + i__   +1+  i__   * a_dim1, 0, lda,
                                              da, da_offset + (i__-1)+1+ (i__-1)*(ldda),  ldda,
                                              queue );
                            // 2. Multiply ---------------------------------------------
                            magma_zgemv(MagmaConjTrans, i__2, i__3, c_one,
                                            da, da_offset + (i__-1)+1+ ((i__-1)+1) * ldda, ldda,
                                            da, da_offset + (i__-1)+1+  (i__-1)    * ldda, c__1,
                                            c_zero, dy, dy_offset, c__1,
                                            queue );

                            // 3. Put the result back ----------------------------------
                            magma_zgetmatrix( i__3, 1,
                                            dy, dy_offset, y_dim1,
                                  y+i__+1+i__*y_dim1, 0, y_dim1,
                                  queue );

                            i__2 = m - i__;
                            i__3 = i__ - 1;
                            blasf77_zgemv(MagmaConjTransStr, &i__2, &i__3, &c_one, &a[i__ + 1 + a_dim1],
                                            &lda, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_zero,
                                            &y[ i__ * y_dim1 + 1], &c__1);
                            i__2 = n - i__;
                            i__3 = i__ - 1;
                            blasf77_zgemv("No transpose", &i__2, &i__3, &c_neg_one,
                                            &y[i__ + 1 + y_dim1], &ldy, &y[i__ * y_dim1 + 1], &c__1,
                                            &c_zero, cpuw1, &c__1);

                            i__2 = m - i__;
                            blasf77_zgemv(MagmaConjTransStr, &i__2, &i__, &c_one, &x[i__ + 1 + x_dim1],
                                            &ldx, &a[i__ + 1 + i__ * a_dim1], &c__1, &c_zero,
                                            &y[i__ * y_dim1 + 1], &c__1);

                            // 4. Synch to make sure the result is back ----------------
                            //magma_event_sync( event );
                            if (i__3!=0){
                                    i__2 = n - i__;
                                    blasf77_zaxpy(&i__2, &c_one, cpuw1,&c__1, &y[i__+1+i__*y_dim1],&c__1);
                            }

                            i__2 = n - i__;
                            blasf77_zgemv(MagmaConjTransStr, &i__, &i__2, &c_neg_one,
                                            &a[(i__ + 1) * a_dim1 + 1], &lda, &y[i__ * y_dim1 + 1],
                                            &c__1, &c_one, &y[i__ + 1 + i__ * y_dim1], &c__1);
                            i__2 = n - i__;
                            blasf77_zscal(&i__2, &tauq[i__], &y[i__ + 1 + i__ * y_dim1], &c__1);
                            #if defined(PRECISION_z) || defined(PRECISION_c)
                    } else {
                            i__2 = n - i__ + 1;
                            lapackf77_zlacgv(&i__2, &a[i__ + i__ * a_dim1], &lda);
                            magma_zsetmatrix( i__2, 1,
                                            a + i__   + (i__  )* a_dim1, 0, lda,
                                            da, da_offset + (i__-1)+ (i__-1)*(ldda), ldda,
                                            queue );
                            #endif
                    }
            }
    }
    
   magma_queue_sync( queue );
   #if defined (ENABLE_TIMER)
   tmag = magma_wtime() - tmag;
   #endif

   magma_free_pinned(cpuw);
   magma_free(dtmp);

   #if defined (ENABLE_TIMER)
   tfin = magma_wtime() - tfin;
   printf("%8.1lf %8.1lf %8.1lf %8.1lf %8.1lf %8.1lf %8.1lf %8.1lf %8.1lf ",tctm1*1000,tgmv1*1000,tmtc1*1000,tctm2*1000,tgmv2*1000,tmtc2*1000,(tctm1+tgmv1+tmtc1+tctm2+tgmv2+tmtc2)*1000,tmag*1000,tfin*1000);
   #endif
    
    return MAGMA_SUCCESS;
} /* magma_zlabrd */

