is hosted in registers and analyze the performance of the resulting kernel.

Implementation
--------------

In this implementation, to avoid repeated global memory accesses, we attempt to fit the matrix in register memory using the same layout as the panel in the QR factorization, i.e. one row per thread; however, the number of registers that a thread uses has an impact on occupancy which can potentially lead to lower performance. In addition, once the register count exceeds the limit set by the GPU’s compute capability, the registers spill into “local" memory which resides in cached slow global memory. Since we store an entire matrix row in the registers of one thread, we use the serial one-sided Jacobi algorithm to compute the SVD where column pairs are processed by the threads one at a time. The bulk of the work lies in the computation of the Gram matrix $G = A_{ij}^T A_{ij}$ (line \[alg:jacobi:gram\] of Algorithm \[alg:jacobi\]) and in the update of the columns (line \[alg:jacobi:rot\]). Since the Gram matrix is symmetric, this boils down to three dot products which are executed as parallel reductions within the warp using warp shuffles. The computation of the $2 \times 2$ rotation matrix as well 