removing the *Hip files from the unsupported/Eigen/CXX11/src/Tensor and unsupported/test directories
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionHip.h b/unsupported/Eigen/CXX11/src/Tensor/TensorContractionHip.h
deleted file mode 100644
index 7561846..0000000
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorContractionHip.h
+++ /dev/null
@@ -1,1521 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014-2015 Benoit Steiner <benoit.steiner.goog@gmail.com>
-// Copyright (C) 2015 Navdeep Jaitly <ndjaitly@google.com>
-// Copyright (C) 2014 Eric Martin <eric@ericmart.in>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_HIP_H
-#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_HIP_H
-
-#if defined(EIGEN_USE_GPU) && defined(EIGEN_HIPCC)
-
-namespace Eigen {
-
-template<typename Scalar, typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper, bool needs_edge_check>
-__device__ EIGEN_STRONG_INLINE void
-EigenContractionKernelInternal(const LhsMapper lhs, const RhsMapper rhs,
-                               const OutputMapper output, Scalar* lhs_shmem, Scalar* rhs_shmem,
-                       const Index m_size, const Index n_size, const Index k_size) {
-
-  const Index m_block_idx = hipBlockIdx_x;
-  const Index n_block_idx = hipBlockIdx_y;
-
-  const Index base_m = 64 * m_block_idx;
-  const Index base_n = 64 * n_block_idx;
-
-  // declare and initialize 64 registers for output 8x8 block
-
-  // prefetch registers
-  Scalar lhs_pf0;
-  Scalar lhs_pf1;
-  Scalar lhs_pf2;
-  Scalar lhs_pf3;
-  Scalar lhs_pf4;
-  Scalar lhs_pf5;
-  Scalar lhs_pf6;
-  Scalar lhs_pf7;
-
-  Scalar rhs_pf0;
-  Scalar rhs_pf1;
-  Scalar rhs_pf2;
-  Scalar rhs_pf3;
-  Scalar rhs_pf4;
-  Scalar rhs_pf5;
-  Scalar rhs_pf6;
-  Scalar rhs_pf7;
-
-  // shared memory is formatted
-  // (contract idx in block, nocontract idx in block, block idx)
-  // where block idx is column major. This transposition limits the number of
-  // bank conflicts when reading the LHS. The core idea is that since the contracting
-  // index is shared by both sides, then the contracting index should be in hipThreadIdx_x.
-
-  // On the LHS, we pad each row inside of each block with an extra element. This makes
-  // each block 8 rows of 9 elements, which is 72 elements. This gives no bank conflicts
-  // on writes and very few 2-way conflicts on reads. There is an 8x8 grid of these blocks.
-
-  // On the RHS we just add 8 padding elements to the end of each block. This gives no bank
-  // conflicts on writes and also none on reads.
-
-  // storage indices
-  const Index lhs_store_idx_base = hipThreadIdx_y * 72 + hipThreadIdx_x * 9 + hipThreadIdx_z;
-  const Index rhs_store_idx_base = hipThreadIdx_y * 72 + hipThreadIdx_z * 8 + hipThreadIdx_x;
-
-  const Index lhs_store_idx_0 = lhs_store_idx_base + 576 * 0;
-  const Index lhs_store_idx_1 = lhs_store_idx_base + 576 * 1;
-  const Index lhs_store_idx_2 = lhs_store_idx_base + 576 * 2;
-  const Index lhs_store_idx_3 = lhs_store_idx_base + 576 * 3;
-  const Index lhs_store_idx_4 = lhs_store_idx_base + 576 * 4;
-  const Index lhs_store_idx_5 = lhs_store_idx_base + 576 * 5;
-  const Index lhs_store_idx_6 = lhs_store_idx_base + 576 * 6;
-  const Index lhs_store_idx_7 = lhs_store_idx_base + 576 * 7;
-
-  const Index rhs_store_idx_0 = rhs_store_idx_base + 576 * 0;
-  const Index rhs_store_idx_1 = rhs_store_idx_base + 576 * 1;
-  const Index rhs_store_idx_2 = rhs_store_idx_base + 576 * 2;
-  const Index rhs_store_idx_3 = rhs_store_idx_base + 576 * 3;
-  const Index rhs_store_idx_4 = rhs_store_idx_base + 576 * 4;
-  const Index rhs_store_idx_5 = rhs_store_idx_base + 576 * 5;
-  const Index rhs_store_idx_6 = rhs_store_idx_base + 576 * 6;
-  const Index rhs_store_idx_7 = rhs_store_idx_base + 576 * 7;
-
-  // in the loading code, the following variables are important:
-  // hipThreadIdx_x: the vertical position in an 8x8 block
-  // hipThreadIdx_y: the vertical index of the 8x8 block in the grid
-  // hipThreadIdx_z: the horizontal position in an 8x8 block
-  // k: the horizontal index of the 8x8 block in the grid
-  //
-  // The k parameter is implicit (it was the loop counter for a loop that went
-  // from 0 to <8, but now that loop is unrolled in the below code.
-
-  const Index load_idx_vert = hipThreadIdx_x + 8 * hipThreadIdx_y;
-  const Index lhs_vert = base_m + load_idx_vert;
-
-#define prefetchIntoRegisters(base_k)                           \
-  {                                                             \
-    lhs_pf0 = conv(0);                                          \
-    lhs_pf1 = conv(0);                                          \
-    lhs_pf2 = conv(0);                                          \
-    lhs_pf3 = conv(0);                                          \
-    lhs_pf4 = conv(0);                                          \
-    lhs_pf5 = conv(0);                                          \
-    lhs_pf6 = conv(0);                                          \
-    lhs_pf7 = conv(0);                                          \
-                                                                \
-    rhs_pf0 = conv(0);                                          \
-    rhs_pf1 = conv(0);                                          \
-    rhs_pf2 = conv(0);                                          \
-    rhs_pf3 = conv(0);                                          \
-    rhs_pf4 = conv(0);                                          \
-    rhs_pf5 = conv(0);                                          \
-    rhs_pf6 = conv(0);                                          \
-    rhs_pf7 = conv(0);                                          \
-                                                                \
-    if (!needs_edge_check || lhs_vert < m_size) {               \
-      const Index lhs_horiz_0 = base_k + hipThreadIdx_z + 0 * 8;   \
-      const Index lhs_horiz_1 = base_k + hipThreadIdx_z + 1 * 8;   \
-      const Index lhs_horiz_2 = base_k + hipThreadIdx_z + 2 * 8;   \
-      const Index lhs_horiz_3 = base_k + hipThreadIdx_z + 3 * 8;   \
-      const Index lhs_horiz_4 = base_k + hipThreadIdx_z + 4 * 8;   \
-      const Index lhs_horiz_5 = base_k + hipThreadIdx_z + 5 * 8;   \
-      const Index lhs_horiz_6 = base_k + hipThreadIdx_z + 6 * 8;   \
-      const Index lhs_horiz_7 = base_k + hipThreadIdx_z + 7 * 8;   \
-                                                                \
-      if (!needs_edge_check || lhs_horiz_7 < k_size) {          \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-        lhs_pf3 = lhs(lhs_vert, lhs_horiz_3);                   \
-        lhs_pf4 = lhs(lhs_vert, lhs_horiz_4);                   \
-        lhs_pf5 = lhs(lhs_vert, lhs_horiz_5);                   \
-        lhs_pf6 = lhs(lhs_vert, lhs_horiz_6);                   \
-        lhs_pf7 = lhs(lhs_vert, lhs_horiz_7);                   \
-      } else if (lhs_horiz_6 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-        lhs_pf3 = lhs(lhs_vert, lhs_horiz_3);                   \
-        lhs_pf4 = lhs(lhs_vert, lhs_horiz_4);                   \
-        lhs_pf5 = lhs(lhs_vert, lhs_horiz_5);                   \
-        lhs_pf6 = lhs(lhs_vert, lhs_horiz_6);                   \
-      } else if (lhs_horiz_5 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-        lhs_pf3 = lhs(lhs_vert, lhs_horiz_3);                   \
-        lhs_pf4 = lhs(lhs_vert, lhs_horiz_4);                   \
-        lhs_pf5 = lhs(lhs_vert, lhs_horiz_5);                   \
-      } else if (lhs_horiz_4 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-        lhs_pf3 = lhs(lhs_vert, lhs_horiz_3);                   \
-        lhs_pf4 = lhs(lhs_vert, lhs_horiz_4);                   \
-      } else if (lhs_horiz_3 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-        lhs_pf3 = lhs(lhs_vert, lhs_horiz_3);                   \
-      } else if (lhs_horiz_2 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-        lhs_pf2 = lhs(lhs_vert, lhs_horiz_2);                   \
-      } else if (lhs_horiz_1 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-        lhs_pf1 = lhs(lhs_vert, lhs_horiz_1);                   \
-      } else if (lhs_horiz_0 < k_size) {                        \
-        lhs_pf0 = lhs(lhs_vert, lhs_horiz_0);                   \
-      }                                                         \
-    }                                                           \
-                                                                \
-    const Index rhs_vert = base_k + load_idx_vert;              \
-    if (!needs_edge_check || rhs_vert < k_size) {               \
-      const Index rhs_horiz_0 = base_n + hipThreadIdx_z + 0 * 8;   \
-      const Index rhs_horiz_1 = base_n + hipThreadIdx_z + 1 * 8;   \
-      const Index rhs_horiz_2 = base_n + hipThreadIdx_z + 2 * 8;   \
-      const Index rhs_horiz_3 = base_n + hipThreadIdx_z + 3 * 8;   \
-      const Index rhs_horiz_4 = base_n + hipThreadIdx_z + 4 * 8;   \
-      const Index rhs_horiz_5 = base_n + hipThreadIdx_z + 5 * 8;   \
-      const Index rhs_horiz_6 = base_n + hipThreadIdx_z + 6 * 8;   \
-      const Index rhs_horiz_7 = base_n + hipThreadIdx_z + 7 * 8;   \
-                                                                \
-      if (rhs_horiz_7 < n_size) {                               \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-        rhs_pf3 = rhs(rhs_vert, rhs_horiz_3);                   \
-        rhs_pf4 = rhs(rhs_vert, rhs_horiz_4);                   \
-        rhs_pf5 = rhs(rhs_vert, rhs_horiz_5);                   \
-        rhs_pf6 = rhs(rhs_vert, rhs_horiz_6);                   \
-        rhs_pf7 = rhs(rhs_vert, rhs_horiz_7);                   \
-      } else if (rhs_horiz_6 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-        rhs_pf3 = rhs(rhs_vert, rhs_horiz_3);                   \
-        rhs_pf4 = rhs(rhs_vert, rhs_horiz_4);                   \
-        rhs_pf5 = rhs(rhs_vert, rhs_horiz_5);                   \
-        rhs_pf6 = rhs(rhs_vert, rhs_horiz_6);                   \
-      } else if (rhs_horiz_5 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-        rhs_pf3 = rhs(rhs_vert, rhs_horiz_3);                   \
-        rhs_pf4 = rhs(rhs_vert, rhs_horiz_4);                   \
-        rhs_pf5 = rhs(rhs_vert, rhs_horiz_5);                   \
-      } else if (rhs_horiz_4 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-        rhs_pf3 = rhs(rhs_vert, rhs_horiz_3);                   \
-        rhs_pf4 = rhs(rhs_vert, rhs_horiz_4);                   \
-      } else if (rhs_horiz_3 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-        rhs_pf3 = rhs(rhs_vert, rhs_horiz_3);                   \
-      } else if (rhs_horiz_2 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-        rhs_pf2 = rhs(rhs_vert, rhs_horiz_2);                   \
-      } else if (rhs_horiz_1 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-        rhs_pf1 = rhs(rhs_vert, rhs_horiz_1);                   \
-      } else if (rhs_horiz_0 < n_size) {                        \
-        rhs_pf0 = rhs(rhs_vert, rhs_horiz_0);                   \
-      }                                                         \
-    }                                                           \
-  }                                                             \
-
-#define writeRegToShmem(_)                      \
-  lhs_shmem[lhs_store_idx_0] = lhs_pf0;         \
-  rhs_shmem[rhs_store_idx_0] = rhs_pf0;         \
-                                                \
-  lhs_shmem[lhs_store_idx_1] = lhs_pf1;         \
-  rhs_shmem[rhs_store_idx_1] = rhs_pf1;         \
-                                                \
-  lhs_shmem[lhs_store_idx_2] = lhs_pf2;         \
-  rhs_shmem[rhs_store_idx_2] = rhs_pf2;         \
-                                                \
-  lhs_shmem[lhs_store_idx_3] = lhs_pf3;         \
-  rhs_shmem[rhs_store_idx_3] = rhs_pf3;         \
-                                                \
-  lhs_shmem[lhs_store_idx_4] = lhs_pf4;         \
-  rhs_shmem[rhs_store_idx_4] = rhs_pf4;         \
-                                                \
-  lhs_shmem[lhs_store_idx_5] = lhs_pf5;         \
-  rhs_shmem[rhs_store_idx_5] = rhs_pf5;         \
-                                                \
-  lhs_shmem[lhs_store_idx_6] = lhs_pf6;         \
-  rhs_shmem[rhs_store_idx_6] = rhs_pf6;         \
-                                                \
-  lhs_shmem[lhs_store_idx_7] = lhs_pf7;         \
-  rhs_shmem[rhs_store_idx_7] = rhs_pf7;         \
-
-  // declare and initialize result array
-#define res(i, j) _res_##i##j
-#define initResultRow(i)                        \
-  Scalar res(i, 0) = conv(0);                   \
-  Scalar res(i, 1) = conv(0);                   \
-  Scalar res(i, 2) = conv(0);                   \
-  Scalar res(i, 3) = conv(0);                   \
-  Scalar res(i, 4) = conv(0);                   \
-  Scalar res(i, 5) = conv(0);                   \
-  Scalar res(i, 6) = conv(0);                   \
-  Scalar res(i, 7) = conv(0);                   \
-
-  internal::scalar_cast_op<int, Scalar> conv;
-  initResultRow(0);
-  initResultRow(1);
-  initResultRow(2);
-  initResultRow(3);
-  initResultRow(4);
-  initResultRow(5);
-  initResultRow(6);
-  initResultRow(7);
-#undef initResultRow
-
-  for (Index base_k = 0; base_k < k_size; base_k += 64) {
-    // wait for previous iteration to finish with shmem. Despite common sense,
-    // the code is a bit faster with this here then at bottom of loop
-    __syncthreads();
-
-    prefetchIntoRegisters(base_k);
-    writeRegToShmem();
-
-    #undef prefetchIntoRegisters
-    #undef writeRegToShmem
-
-    // wait for shared mem packing to be done before starting computation
-    __syncthreads();
-
-    // compute 8x8 matrix product by outer product. This involves packing one column
-    // of LHS and one row of RHS into registers (takes 16 registers).
-
-#define lcol(i) _lcol##i
-    Scalar lcol(0);
-    Scalar lcol(1);
-    Scalar lcol(2);
-    Scalar lcol(3);
-    Scalar lcol(4);
-    Scalar lcol(5);
-    Scalar lcol(6);
-    Scalar lcol(7);
-
-#define rrow(j) _rrow##j
-    Scalar rrow(0);
-    Scalar rrow(1);
-    Scalar rrow(2);
-    Scalar rrow(3);
-    Scalar rrow(4);
-    Scalar rrow(5);
-    Scalar rrow(6);
-    Scalar rrow(7);
-
-    // Now x corresponds to k, y to m, and z to n
-    const Scalar* lhs_block = &lhs_shmem[hipThreadIdx_x + 9 * hipThreadIdx_y];
-    const Scalar* rhs_block = &rhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_z];
-
-#define lhs_element(i, j) lhs_block[72 * ((i) + 8 * (j))]
-#define rhs_element(i, j) rhs_block[72 * ((i) + 8 * (j))]
-
-#define loadData(i, j)                          \
-    lcol(0) = lhs_element(0, j);               \
-    rrow(0) = rhs_element(i, 0);               \
-    lcol(1) = lhs_element(1, j);               \
-    rrow(1) = rhs_element(i, 1);               \
-    lcol(2) = lhs_element(2, j);               \
-    rrow(2) = rhs_element(i, 2);               \
-    lcol(3) = lhs_element(3, j);               \
-    rrow(3) = rhs_element(i, 3);               \
-    lcol(4) = lhs_element(4, j);               \
-    rrow(4) = rhs_element(i, 4);               \
-    lcol(5) = lhs_element(5, j);               \
-    rrow(5) = rhs_element(i, 5);               \
-    lcol(6) = lhs_element(6, j);               \
-    rrow(6) = rhs_element(i, 6);               \
-    lcol(7) = lhs_element(7, j);               \
-    rrow(7) = rhs_element(i, 7);               \
-
-#define computeCol(j)                           \
-    res(0, j) += lcol(0) * rrow(j);             \
-    res(1, j) += lcol(1) * rrow(j);             \
-    res(2, j) += lcol(2) * rrow(j);             \
-    res(3, j) += lcol(3) * rrow(j);             \
-    res(4, j) += lcol(4) * rrow(j);             \
-    res(5, j) += lcol(5) * rrow(j);             \
-    res(6, j) += lcol(6) * rrow(j);             \
-    res(7, j) += lcol(7) * rrow(j);             \
-
-#define computePass(i)                          \
-    loadData(i, i);                             \
-                                                \
-    computeCol(0);                              \
-    computeCol(1);                              \
-    computeCol(2);                              \
-    computeCol(3);                              \
-    computeCol(4);                              \
-    computeCol(5);                              \
-    computeCol(6);                              \
-    computeCol(7);                              \
-
-    computePass(0);
-    computePass(1);
-    computePass(2);
-    computePass(3);
-    computePass(4);
-    computePass(5);
-    computePass(6);
-    computePass(7);
-
-#undef lcol
-#undef rrow
-#undef lhs_element
-#undef rhs_element
-#undef loadData
-#undef computeCol
-#undef computePass
-  } // end loop over k
-
-  // we've now iterated over all of the large (ie width 64) k blocks and
-  // accumulated results in registers. At this point thread (x, y, z) contains
-  // the sum across all big k blocks of the product of little k block of index (x, y)
-  // with block of index (y, z). To compute the final output, we need to reduce
-  // the 8 threads over y by summation.
-#define shuffleInc(i, j, mask) res(i, j) += __shfl_xor(res(i, j), mask)
-
-#define reduceRow(i, mask)                      \
-  shuffleInc(i, 0, mask);                       \
-  shuffleInc(i, 1, mask);                       \
-  shuffleInc(i, 2, mask);                       \
-  shuffleInc(i, 3, mask);                       \
-  shuffleInc(i, 4, mask);                       \
-  shuffleInc(i, 5, mask);                       \
-  shuffleInc(i, 6, mask);                       \
-  shuffleInc(i, 7, mask);                       \
-
-#define reduceMatrix(mask)                      \
-  reduceRow(0, mask);                           \
-  reduceRow(1, mask);                           \
-  reduceRow(2, mask);                           \
-  reduceRow(3, mask);                           \
-  reduceRow(4, mask);                           \
-  reduceRow(5, mask);                           \
-  reduceRow(6, mask);                           \
-  reduceRow(7, mask);                           \
-
-  // actually perform the reduction, now each thread of index (_, y, z)
-  // contains the correct values in its registers that belong in the output
-  // block
-  reduceMatrix(1);
-  reduceMatrix(2);
-  reduceMatrix(4);
-
-#undef shuffleInc
-#undef reduceRow
-#undef reduceMatrix
-
-  // now we need to copy the 64 values into main memory. We can't split work
-  // among threads because all variables are in registers. There's 2 ways
-  // to do this:
-  // (1) have 1 thread do 64 writes from registers into global memory
-  // (2) have 1 thread do 64 writes into shared memory, and then 8 threads
-  //     each do 8 writes into global memory. We can just overwrite the shared
-  //     memory from the problem we just solved.
-  // (2) is slightly faster than (1) due to less branching and more ILP
-
-  // TODO: won't yield much gain, but could just use currently unused shared mem
-  //       and then we won't have to sync
-  // wait for shared mem to be out of use
-  __syncthreads();
-
-#define writeResultShmem(i, j)                                          \
-  lhs_shmem[i + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * j] = res(i, j); \
-
-#define writeRow(i)                             \
-  writeResultShmem(i, 0);                       \
-  writeResultShmem(i, 1);                       \
-  writeResultShmem(i, 2);                       \
-  writeResultShmem(i, 3);                       \
-  writeResultShmem(i, 4);                       \
-  writeResultShmem(i, 5);                       \
-  writeResultShmem(i, 6);                       \
-  writeResultShmem(i, 7);                       \
-
-  if (hipThreadIdx_x == 0) {
-    writeRow(0);
-    writeRow(1);
-    writeRow(2);
-    writeRow(3);
-    writeRow(4);
-    writeRow(5);
-    writeRow(6);
-    writeRow(7);
-  }
-#undef writeResultShmem
-#undef writeRow
-
-  const int max_i_write = numext::mini((int)((m_size - base_m - hipThreadIdx_y + 7) / 8), 8);
-  const int max_j_write = numext::mini((int)((n_size - base_n - hipThreadIdx_z + 7) / 8), 8);
-
-  if (hipThreadIdx_x < max_i_write) {
-    if (max_j_write == 8) {
-      // TODO: can i trade bank conflicts for coalesced writes?
-      Scalar val0 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 0];
-      Scalar val1 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 1];
-      Scalar val2 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 2];
-      Scalar val3 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 3];
-      Scalar val4 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 4];
-      Scalar val5 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 5];
-      Scalar val6 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 6];
-      Scalar val7 = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * 7];
-
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 0) = val0;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 1) = val1;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 2) = val2;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 3) = val3;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 4) = val4;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 5) = val5;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 6) = val6;
-      output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * 7) = val7;
-    } else {
-#pragma unroll 7
-      for (int j = 0; j < max_j_write; j++) {
-        Scalar val = lhs_shmem[hipThreadIdx_x + 8 * hipThreadIdx_y + 64 * hipThreadIdx_z + 512 * j];
-        output(base_m + hipThreadIdx_y + 8 * hipThreadIdx_x, base_n + hipThreadIdx_z + 8 * j) = val;
-      }
-    }
-  }
-#undef res
-}
-
-
-template<typename Scalar, typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper>
-__global__ void
-__launch_bounds__(512, 1)
-EigenContractionKernel(const LhsMapper lhs, const RhsMapper rhs,
-                       const OutputMapper output,
-                       const Index m_size, const Index n_size, const Index k_size) {
-  __shared__ Scalar lhs_shmem[72 * 64];
-  __shared__ Scalar rhs_shmem[72 * 64];
-
-  const Index m_block_idx = hipBlockIdx_x;
-  const Index n_block_idx = hipBlockIdx_y;
-
-  const Index base_m = 64 * m_block_idx;
-  const Index base_n = 64 * n_block_idx;
-
-  if (base_m + 63 < m_size && base_n + 63 < n_size) {
-    EigenContractionKernelInternal<Scalar, Index, LhsMapper, RhsMapper, OutputMapper, false>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size);
-  } else {
-    EigenContractionKernelInternal<Scalar, Index, LhsMapper, RhsMapper, OutputMapper, true>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size);
-  }
-}
-
-
-template<typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper, bool CHECK_LHS_BOUNDARY,
-         bool CHECK_RHS_BOUNDARY>
-__device__ EIGEN_STRONG_INLINE void
-EigenFloatContractionKernelInternal16x16(const LhsMapper lhs, const RhsMapper rhs,
-                       const OutputMapper output, float2 lhs_shmem2[][16],
-                       float2 rhs_shmem2[][8], const Index m_size,
-                       const Index n_size, const Index k_size,
-                       const Index base_m, const Index base_n) {
-
-  // prefetch registers
-  float4 lhs_pf0, rhs_pf0;
-
-  float4 results[4];
-  for (int i=0; i < 4; i++) {
-    results[i].x = results[i].y = results[i].z = results[i].w = 0;
-  }
-
-
-#define prefetch_lhs(reg, row, col)                   \
-    if (!CHECK_LHS_BOUNDARY) {                        \
-      if (col < k_size) {                             \
-        /*reg = lhs.template loadPacket<Unaligned>(row, col);*/     \
-        reg.x =lhs(row + 0, col);                     \
-        reg.y =lhs(row + 1, col);                     \
-        reg.z =lhs(row + 2, col);                     \
-        reg.w =lhs(row + 3, col);                     \
-      }                                               \
-    } else {                                          \
-      if (col < k_size) {                             \
-        if (row + 3 < m_size) {                       \
-          /*reg =lhs.template loadPacket<Unaligned>(row, col);*/   \
-          reg.x =lhs(row + 0, col);                   \
-          reg.y =lhs(row + 1, col);                   \
-          reg.z =lhs(row + 2, col);                   \
-          reg.w =lhs(row + 3, col);                   \
-        } else if (row + 2 < m_size) {                \
-          reg.x =lhs(row + 0, col);                   \
-          reg.y =lhs(row + 1, col);                   \
-          reg.z =lhs(row + 2, col);                   \
-        } else if (row + 1 < m_size) {                \
-          reg.x =lhs(row + 0, col);                   \
-          reg.y =lhs(row + 1, col);                   \
-        } else if (row  < m_size) {                   \
-          reg.x =lhs(row + 0, col);                   \
-        }                                             \
-      }                                               \
-    }                                                 \
-
-
-  Index lhs_vert = base_m+hipThreadIdx_x*4;
-
-  for (Index k = 0; k < k_size; k += 16) {
-    //lhs_pf0 = internal::pset1<float4>(0);
-    //rhs_pf0 = internal::pset1<float4>(0);
-    lhs_pf0 = make_float4(0, 0, 0, 0);
-    rhs_pf0 = make_float4(0, 0, 0, 0);
-
-    Index lhs_horiz = hipThreadIdx_y+k;
-    prefetch_lhs(lhs_pf0, lhs_vert, lhs_horiz)
-
-    Index rhs_vert = k+(hipThreadIdx_x%4)*4;
-    Index rhs_horiz0 = (hipThreadIdx_x>>2)+hipThreadIdx_y*4+base_n;
-
-    if (!CHECK_RHS_BOUNDARY) {
-      if ((rhs_vert + 3) < k_size) {
-        // just CHECK_RHS_BOUNDARY
-        //rhs_pf0 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz0);
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-        rhs_pf0.w = rhs(rhs_vert + 3, rhs_horiz0);
-      } else if (rhs_vert + 2 < k_size) {
-        // just CHECK_RHS_BOUNDARY
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-      } else if (rhs_vert + 1 < k_size) {
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-      } else if (rhs_vert  < k_size) {
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-      }
-    } else {
-      if (rhs_horiz0 < n_size) {
-        if ((rhs_vert + 3) < k_size) {
-          //rhs_pf0 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz0);
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-          rhs_pf0.w = rhs(rhs_vert + 3, rhs_horiz0);
-        } else if ((rhs_vert + 2) < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-        } else if ((rhs_vert + 1) < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        } else if (rhs_vert  < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        }
-      }
-    }
-    float x1, x2 ;
-    // the following can be a bitwise operation..... some day.
-    if((hipThreadIdx_x%8) < 4) {
-      x1 = rhs_pf0.y;
-      x2 = rhs_pf0.w;
-    } else {
-      x1 = rhs_pf0.x;
-      x2 = rhs_pf0.z;
-    }
-    x1 = __shfl_xor(x1, 4);
-    x2 = __shfl_xor(x2, 4);
-    if((hipThreadIdx_x%8) < 4) {
-      rhs_pf0.y = x1;
-      rhs_pf0.w = x2;
-    } else {
-      rhs_pf0.x = x1;
-      rhs_pf0.z = x2;
-    }
-
-    // We have 64 features.
-    // Row 0 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 0, 1.
-    // Row 1 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 2, 3.
-    // ...
-    // Row 31 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 62, 63
-    // Row 32 -> times (2, 6, 10, 14, 3, 7, 11, 15) for features 0, 1
-    // ...
-    rhs_shmem2[(hipThreadIdx_x>>3)+ hipThreadIdx_y*2][hipThreadIdx_x%8] = make_float2(rhs_pf0.x, rhs_pf0.y);
-    rhs_shmem2[(hipThreadIdx_x>>3)+ hipThreadIdx_y*2+32][hipThreadIdx_x%8] = make_float2(rhs_pf0.z, rhs_pf0.w);
-
-    // Row 0 (time 0) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), ..  (60, 61)
-    // Row 1 (time 1) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), ..  (60, 61)
-    // ...
-    // Row 15 (time 15) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), ..  (60, 61)
-    // Row 16 (time 0) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), ..  (62, 63)
-    // ...
-
-    lhs_shmem2[hipThreadIdx_y][hipThreadIdx_x] = make_float2(lhs_pf0.x, lhs_pf0.y);
-    lhs_shmem2[hipThreadIdx_y+16][hipThreadIdx_x] = make_float2(lhs_pf0.z, lhs_pf0.w);
-
-
-#define add_vals(fl1, fl2, fr1, fr2)\
-    results[0].x += fl1.x * fr1.x;\
-    results[0].y += fl1.y * fr1.x;\
-    results[0].z += fl2.x * fr1.x;\
-    results[0].w += fl2.y * fr1.x;\
-\
-    results[1].x += fl1.x * fr1.y;\
-    results[1].y += fl1.y * fr1.y;\
-    results[1].z += fl2.x * fr1.y;\
-    results[1].w += fl2.y * fr1.y;\
-\
-    results[2].x += fl1.x * fr2.x;\
-    results[2].y += fl1.y * fr2.x;\
-    results[2].z += fl2.x * fr2.x;\
-    results[2].w += fl2.y * fr2.x;\
-\
-    results[3].x += fl1.x * fr2.y;\
-    results[3].y += fl1.y * fr2.y;\
-    results[3].z += fl2.x * fr2.y;\
-    results[3].w += fl2.y * fr2.y;\
-
-    __syncthreads();
-
-    // Do the multiplies.
-    #pragma unroll
-    for (int koff = 0; koff < 16; koff ++) {
-      // 32 x threads.
-      float2 fl1 = lhs_shmem2[koff][hipThreadIdx_x];
-      float2 fl2 = lhs_shmem2[koff + 16][hipThreadIdx_x];
-
-      int start_feature = hipThreadIdx_y * 4;
-      float2 fr1 = rhs_shmem2[(start_feature>>1) + 32*((koff%4)/2)][koff/4 + (koff%2)*4];
-      float2 fr2 = rhs_shmem2[(start_feature>>1) + 1 + 32*((koff%4)/2)][koff/4 + (koff%2)*4];
-
-      add_vals(fl1, fl2, fr1, fr2)
-    }
-    __syncthreads();
-  }
-
-#undef prefetch_lhs
-#undef add_vals
-
-  Index horiz_base = hipThreadIdx_y*4+base_n;
-  if (!CHECK_LHS_BOUNDARY && !CHECK_RHS_BOUNDARY) {
-    for (int i = 0; i < 4; i++) {
-      output(lhs_vert, horiz_base + i) = results[i].x;
-      output(lhs_vert + 1, horiz_base + i) = results[i].y;
-      output(lhs_vert + 2, horiz_base + i) = results[i].z;
-      output(lhs_vert + 3, horiz_base + i) = results[i].w;
-    }
-  } else if (!CHECK_RHS_BOUNDARY) {
-    // CHECK LHS
-    if (lhs_vert + 3 < m_size) {
-      for (int i = 0; i < 4; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        output(lhs_vert + 3, horiz_base + i) = results[i].w;
-      }
-    } else if (lhs_vert + 2 < m_size) {
-      for (int i = 0; i < 4; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-      }
-    } else if (lhs_vert + 1 < m_size) {
-      for (int i = 0; i < 4; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-      }
-    } else if (lhs_vert  < m_size) {
-      for (int i = 0; i < 4; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-      }
-    }
-  } else if (!CHECK_LHS_BOUNDARY) {
-    // CHECK RHS
-    /*
-    int ncols_rem = fminf(n_size- horiz_base, 4);
-    for (int i = 0; i < ncols_rem; i++) {
-      output(lhs_vert, horiz_base + i) = results[i].x;
-      output(lhs_vert + 1, horiz_base + i) = results[i].y;
-      output(lhs_vert + 2, horiz_base + i) = results[i].z;
-      output(lhs_vert + 3, horiz_base + i) = results[i].w;
-    }*/
-    for (int i = 0; i < 4; i++) {
-      if (horiz_base+i < n_size) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        output(lhs_vert + 3, horiz_base + i) = results[i].w;
-       }
-    }
-  } else {
-    // CHECK both boundaries.
-    for (int i = 0; i < 4; i++) {
-      if (horiz_base+i < n_size) {
-        if (lhs_vert < m_size)
-          output(lhs_vert, horiz_base + i) = results[i].x;
-        if (lhs_vert + 1 < m_size)
-          output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        if (lhs_vert + 2 < m_size)
-          output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        if (lhs_vert + 3 < m_size)
-          output(lhs_vert + 3, horiz_base + i) = results[i].w;
-      }
-    }
-  }
-}
-
-
-template<typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper, bool CHECK_LHS_BOUNDARY,
-         bool CHECK_RHS_BOUNDARY>
-__device__ EIGEN_STRONG_INLINE void
-EigenFloatContractionKernelInternal(const LhsMapper lhs, const RhsMapper rhs,
-                       const OutputMapper output, float2 lhs_shmem2[][32],
-                       float2 rhs_shmem2[][8], const Index m_size,
-                       const Index n_size, const Index k_size,
-                       const Index base_m, const Index base_n) {
-
-  // prefetch registers
-  float4 lhs_pf0, lhs_pf1, lhs_pf2, lhs_pf3;
-  float4 rhs_pf0, rhs_pf1;
-
-  float4 results[8];
-  for (int i=0; i < 8; i++) {
-    results[i].x = results[i].y = results[i].z = results[i].w = 0;
-  }
-
-
-  Index lhs_vert = base_m+hipThreadIdx_x*4+(hipThreadIdx_y%4)*32;
-  for (Index k = 0; k < k_size; k += 32) {
-    /*lhs_pf0 = internal::pset1<float4>(0);
-    lhs_pf1 = internal::pset1<float4>(0);
-    lhs_pf2 = internal::pset1<float4>(0);
-    lhs_pf3 = internal::pset1<float4>(0);
-
-    rhs_pf0 = internal::pset1<float4>(0);
-    rhs_pf1 = internal::pset1<float4>(0);*/
-
-
-    lhs_pf0 = make_float4(0, 0, 0, 0);
-    lhs_pf1 = make_float4(0, 0, 0, 0);
-    lhs_pf2 = make_float4(0, 0, 0, 0);
-    lhs_pf3 = make_float4(0, 0, 0, 0);
-
-    rhs_pf0 = make_float4(0, 0, 0, 0);
-    rhs_pf1 = make_float4(0, 0, 0, 0);
-
-     if (!CHECK_LHS_BOUNDARY) {
-      if ((hipThreadIdx_y/4+k+24) < k_size) {
-        //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-        //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-        //lhs_pf2 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+16));
-        //lhs_pf3 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+24));
-        lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-        lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-        lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-        lhs_pf3.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+24));
-        lhs_pf3.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+24));
-        lhs_pf3.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+24));
-        lhs_pf3.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+24));
-      } else if ((hipThreadIdx_y/4+k+16) < k_size) {
-        //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-        //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-        //lhs_pf2 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+16));
-        lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-        lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-        lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-        lhs_pf2.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-      } else if ((hipThreadIdx_y/4+k+8) < k_size) {
-        //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-        //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-        lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-        lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-        lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-      } else if ((hipThreadIdx_y/4+k) < k_size) {
-        //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-        lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-        lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-        lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-      }
-    } else {
-      // just CHECK_LHS_BOUNDARY
-      if (lhs_vert + 3 < m_size) {
-        if ((hipThreadIdx_y/4+k+24) < k_size) {
-          //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-          //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-          //lhs_pf2 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+16));
-          //lhs_pf3 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+24));
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-          lhs_pf3.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+24));
-        } else if ((hipThreadIdx_y/4+k+16) < k_size) {
-          //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-          //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-          //lhs_pf2 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+16));
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-        } else if ((hipThreadIdx_y/4+k+8) < k_size) {
-          //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-          //lhs_pf1 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k+8));
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        } else if ((hipThreadIdx_y/4+k) < k_size) {
-          //lhs_pf0 =lhs.template loadPacket<Unaligned>(lhs_vert, (hipThreadIdx_y/4+k));
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf0.w =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        }
-      } else if (lhs_vert + 2 < m_size) {
-        if ((hipThreadIdx_y/4+k+24) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-          lhs_pf3.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+24));
-        } else if ((hipThreadIdx_y/4+k+16) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+16));
-        } else if ((hipThreadIdx_y/4+k+8) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k+8));
-        } else if ((hipThreadIdx_y/4+k) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf0.z =lhs(lhs_vert + 2, (hipThreadIdx_y/4+k));
-        }
-      } else if (lhs_vert + 1 < m_size) {
-        if ((hipThreadIdx_y/4+k+24) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-          lhs_pf3.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+24));
-          lhs_pf3.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+24));
-        } else if ((hipThreadIdx_y/4+k+16) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf2.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+16));
-        } else if ((hipThreadIdx_y/4+k+8) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf1.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k+8));
-        } else if ((hipThreadIdx_y/4+k) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf0.y =lhs(lhs_vert + 1, (hipThreadIdx_y/4+k));
-        }
-      } else if (lhs_vert < m_size) {
-        if ((hipThreadIdx_y/4+k+24) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-          lhs_pf3.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+24));
-        } else if ((hipThreadIdx_y/4+k+16) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-          lhs_pf2.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+16));
-        } else if ((hipThreadIdx_y/4+k+8) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-          lhs_pf1.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k+8));
-        } else if ((hipThreadIdx_y/4+k) < k_size) {
-          lhs_pf0.x =lhs(lhs_vert + 0, (hipThreadIdx_y/4+k));
-        }
-      }
-    }
-    __syncthreads();
-    Index rhs_vert = k+hipThreadIdx_x*4;
-    Index rhs_horiz0 = hipThreadIdx_y*2+base_n;
-    Index rhs_horiz1 = hipThreadIdx_y*2+1+base_n;
-    if (!CHECK_RHS_BOUNDARY) {
-      if ((rhs_vert + 3) < k_size) {
-        // just CHECK_RHS_BOUNDARY
-        //rhs_pf0 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz0);
-        //rhs_pf1 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz1);
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-        rhs_pf0.w = rhs(rhs_vert + 3, rhs_horiz0);
-        rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-        rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-        rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1);
-        rhs_pf1.w = rhs(rhs_vert + 3, rhs_horiz1);
-      } else if (rhs_vert + 2 < k_size) {
-        // just CHECK_RHS_BOUNDARY
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-        rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-        rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-        rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1);
-      } else if (rhs_vert + 1 < k_size) {
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-        rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-      } else if (rhs_vert  < k_size) {
-        rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-      }
-    } else {
-      if (rhs_horiz1 < n_size) {
-        if ((rhs_vert + 3) < k_size) {
-          // just CHECK_RHS_BOUNDARY
-          //rhs_pf0 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz0);
-          //rhs_pf1 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz1);
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-          rhs_pf0.w = rhs(rhs_vert + 3, rhs_horiz0);
-          rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-          rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-          rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1);
-          rhs_pf1.w = rhs(rhs_vert + 3, rhs_horiz1);
-        } else if (rhs_vert + 2 < k_size) {
-          // just CHECK_RHS_BOUNDARY
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-          rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-          rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-          rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1);
-        } else if (k+hipThreadIdx_x*4 + 1 < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-          rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1);
-        } else if (k+hipThreadIdx_x*4  < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf1.x = rhs(rhs_vert, rhs_horiz1);
-        }
-      } else if (rhs_horiz0 < n_size) {
-        if ((rhs_vert + 3) < k_size) {
-          // just CHECK_RHS_BOUNDARY
-          //rhs_pf0 = rhs.template loadPacket<Unaligned>(rhs_vert, rhs_horiz0);
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-          rhs_pf0.w = rhs(rhs_vert + 3, rhs_horiz0);
-        } else if ((rhs_vert + 2) < k_size) {
-          // just CHECK_RHS_BOUNDARY
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-          rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0);
-        } else if ((rhs_vert + 1) < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-          rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0);
-        } else if (rhs_vert  < k_size) {
-          rhs_pf0.x = rhs(rhs_vert, rhs_horiz0);
-        }
-      }
-    }
-    __syncthreads();
-    // Loaded. Do computation
-    // Row 0 -> times (0, 4, 8, .. 28) for features 0, 1.
-    // Row 1 -> times (0, 4, 8, .. 28) for features 2, 3.
-    // ..
-    // Row 31 -> times (0, 4, 8, .. 28) for features 62, 63
-    rhs_shmem2[hipThreadIdx_y][hipThreadIdx_x] = make_float2(rhs_pf0.x, rhs_pf1.x);
-    // Row 32 -> times (1, 5, 9, .. 29) for features 0, 1.
-    // Row 33 -> times (1, 5, 9, .. 29) for features 2, 3.
-    // ..
-    rhs_shmem2[hipThreadIdx_y+32][hipThreadIdx_x] = make_float2(rhs_pf0.y, rhs_pf1.y);
-    // Row 64 -> times (2, 6, 10, .. 30) for features 0, 1.
-    // Row 65 -> times (2, 6, 10, .. 30) for features 2, 3.
-    rhs_shmem2[hipThreadIdx_y+64][hipThreadIdx_x] = make_float2(rhs_pf0.z, rhs_pf1.z);
-    // Row 96 -> times (3, 7, 11, .. 31) for features 0, 1.
-    // Row 97 -> times (3, 7, 11, .. 31) for features 2, 3.
-    rhs_shmem2[hipThreadIdx_y+96][hipThreadIdx_x] = make_float2(rhs_pf0.w, rhs_pf1.w);
-
-    // LHS.
-    // Row 0 (time 0) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), ..  (60, 61) .. (124, 125)
-    // Row 1 (time 1) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), ..  (60, 61) .. (124, 125)
-    // ...
-    // Row 8 (time 0) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), ..  (62, 63) .. (126, 127)
-    // Row 15 (time 7) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), ..  (62, 63) .. (126, 127)
-
-
-#define add_vals(a_feat1, a_feat2, f1, f2, f3, f4)\
-      results[0].x += a_feat1.x * f1.x;\
-      results[1].x += a_feat1.x * f1.y;\
-      results[2].x += a_feat1.x * f2.x;\
-      results[3].x += a_feat1.x * f2.y;\
-      results[4].x += a_feat1.x * f3.x;\
-      results[5].x += a_feat1.x * f3.y;\
-      results[6].x += a_feat1.x * f4.x;\
-      results[7].x += a_feat1.x * f4.y;\
-\
-      results[0].y += a_feat1.y * f1.x;\
-      results[1].y += a_feat1.y * f1.y;\
-      results[2].y += a_feat1.y * f2.x;\
-      results[3].y += a_feat1.y * f2.y;\
-      results[4].y += a_feat1.y * f3.x;\
-      results[5].y += a_feat1.y * f3.y;\
-      results[6].y += a_feat1.y * f4.x;\
-      results[7].y += a_feat1.y * f4.y;\
-\
-      results[0].z += a_feat2.x * f1.x;\
-      results[1].z += a_feat2.x * f1.y;\
-      results[2].z += a_feat2.x * f2.x;\
-      results[3].z += a_feat2.x * f2.y;\
-      results[4].z += a_feat2.x * f3.x;\
-      results[5].z += a_feat2.x * f3.y;\
-      results[6].z += a_feat2.x * f4.x;\
-      results[7].z += a_feat2.x * f4.y;\
-\
-      results[0].w += a_feat2.y * f1.x;\
-      results[1].w += a_feat2.y * f1.y;\
-      results[2].w += a_feat2.y * f2.x;\
-      results[3].w += a_feat2.y * f2.y;\
-      results[4].w += a_feat2.y * f3.x;\
-      results[5].w += a_feat2.y * f3.y;\
-      results[6].w += a_feat2.y * f4.x;\
-      results[7].w += a_feat2.y * f4.y;\
-
-    lhs_shmem2[hipThreadIdx_y/4][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf0.x, lhs_pf0.y);
-    lhs_shmem2[hipThreadIdx_y/4+8][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf1.x, lhs_pf1.y);
-    lhs_shmem2[hipThreadIdx_y/4+16][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf2.x, lhs_pf2.y);
-    lhs_shmem2[hipThreadIdx_y/4+24][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf3.x, lhs_pf3.y);
-
-    lhs_shmem2[hipThreadIdx_y/4 + 32][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf0.z, lhs_pf0.w);
-    lhs_shmem2[hipThreadIdx_y/4 + 40][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf1.z, lhs_pf1.w);
-    lhs_shmem2[hipThreadIdx_y/4 + 48][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf2.z, lhs_pf2.w);
-    lhs_shmem2[hipThreadIdx_y/4 + 56][hipThreadIdx_x+(hipThreadIdx_y%4)*8] = make_float2(lhs_pf3.z, lhs_pf3.w);
-
-    __syncthreads();
-
-    // Do the multiplies.
-    #pragma unroll
-    for (int koff = 0; koff < 32; koff ++) {
-      float2 a3 = lhs_shmem2[koff][hipThreadIdx_x + (hipThreadIdx_y % 4) * 8];
-      float2 a4 = lhs_shmem2[koff + 32][hipThreadIdx_x + (hipThreadIdx_y % 4) * 8];
-
-      // first feature is at (hipThreadIdx_y/4) * 8 last is at start + 8.
-      int start_feature = (hipThreadIdx_y / 4) * 8;
-
-      float2 br1 = rhs_shmem2[start_feature/2 +     (koff % 4) * 32][koff/4];
-      float2 br2 = rhs_shmem2[start_feature/2 + 1 + (koff % 4) * 32][koff/4];
-      float2 br3 = rhs_shmem2[start_feature/2 + 2 + (koff % 4) * 32][koff/4];
-      float2 br4 = rhs_shmem2[start_feature/2 + 3 + (koff % 4) * 32][koff/4];
-
-      add_vals(a3, a4, br1, br2, br3, br4)
-    }
-    __syncthreads();
-  } // end loop over k
-
-
-  __syncthreads();
-  Index horiz_base = (hipThreadIdx_y/4)*8+base_n;
-  if (!CHECK_LHS_BOUNDARY && !CHECK_RHS_BOUNDARY) {
-    for (int i = 0; i < 8; i++) {
-      output(lhs_vert, horiz_base + i) = results[i].x;
-      output(lhs_vert + 1, horiz_base + i) = results[i].y;
-      output(lhs_vert + 2, horiz_base + i) = results[i].z;
-      output(lhs_vert + 3, horiz_base + i) = results[i].w;
-    }
-  } else if (!CHECK_RHS_BOUNDARY) {
-    if (lhs_vert + 3 < m_size) {
-      for (int i = 0; i < 8; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        output(lhs_vert + 3, horiz_base + i) = results[i].w;
-      }
-    } else if (lhs_vert + 2 < m_size) {
-      for (int i = 0; i < 8; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-      }
-    } else if (lhs_vert + 1 < m_size) {
-      for (int i = 0; i < 8; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-      }
-    } else if (lhs_vert  < m_size) {
-      for (int i = 0; i < 8; i++) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-      }
-    }
-  } else if (!CHECK_LHS_BOUNDARY) {
-    // CHECK BOUNDARY_B
-    for (int i = 0; i < 8; i++) {
-      if (horiz_base + i < n_size) {
-        output(lhs_vert, horiz_base + i) = results[i].x;
-        output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        output(lhs_vert + 3, horiz_base + i) = results[i].w;
-      }
-    }
-  } else {
-    // CHECK both boundaries.
-    for (int i = 0; i < 8; i++) {
-      if (horiz_base + i < n_size) {
-        if (lhs_vert < m_size)
-          output(lhs_vert, horiz_base + i) = results[i].x;
-        if (lhs_vert + 1 < m_size)
-          output(lhs_vert + 1, horiz_base + i) = results[i].y;
-        if (lhs_vert + 2 < m_size)
-          output(lhs_vert + 2, horiz_base + i) = results[i].z;
-        if (lhs_vert + 3 < m_size)
-          output(lhs_vert + 3, horiz_base + i) = results[i].w;
-      }
-    }
-  }
-}
-
-
-template<typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper>
-__global__ void
-__launch_bounds__(256, 1)
-EigenFloatContractionKernel(const LhsMapper lhs, const RhsMapper rhs,
-                       const OutputMapper output,
-                       const Index m_size, const Index n_size, const Index k_size) {
-  __shared__ float2 lhs_shmem[64*32];
-  __shared__ float2 rhs_shmem[128*8];
-
-  typedef float2 LHS_MEM[64][32];
-  typedef float2 RHS_MEM[128][8];
-
-  typedef float2 LHS_MEM16x16[32][16];
-  typedef float2 RHS_MEM16x16[64][8];
-
-  const Index m_block_idx = hipBlockIdx_x;
-  const Index n_block_idx = hipBlockIdx_y;
-
-  const Index base_m = 128 * m_block_idx;
-  const Index base_n = 64 * n_block_idx;
-
-  bool check_rhs = (base_n + 63) >= n_size;
-  bool check_lhs128 = (base_m + 127) >= m_size;
-
-  if (!check_rhs) {
-    if (!check_lhs128) {
-      // >= 128 rows left
-      EigenFloatContractionKernelInternal<Index, LhsMapper, RhsMapper, OutputMapper, false, false>(
-                     lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n);
-    } else {
-      EigenFloatContractionKernelInternal<Index, LhsMapper, RhsMapper, OutputMapper, true, false>(
-                     lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n);
-    }
-  } else {
-    if (!check_lhs128) {
-      // >= 128 rows left
-      EigenFloatContractionKernelInternal<Index, LhsMapper, RhsMapper, OutputMapper, false, true>(
-                     lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n);
-    } else {
-      EigenFloatContractionKernelInternal<Index, LhsMapper, RhsMapper, OutputMapper, true, true>(
-                     lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n);
-    }
-  }
-}
-
-template<typename Index, typename LhsMapper,
-         typename RhsMapper, typename OutputMapper>
-__global__ void
-__launch_bounds__(256, 1)
-EigenFloatContractionKernel16x16(const LhsMapper lhs, const RhsMapper rhs,
-                       const OutputMapper output,
-                       const Index m_size, const Index n_size, const Index k_size) {
-  __shared__ float2 lhs_shmem[32][16];
-  __shared__ float2 rhs_shmem[64][8];
-
-  const Index m_block_idx = hipBlockIdx_x;
-  const Index n_block_idx = hipBlockIdx_y;
-
-  const Index base_m = 64 * m_block_idx;
-  const Index base_n = 64 * n_block_idx;
-
-  if (base_m + 63 < m_size) {
-    if (base_n + 63 < n_size) {
-      EigenFloatContractionKernelInternal16x16<Index, LhsMapper, RhsMapper, OutputMapper, false, false>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n);
-    } else {
-      EigenFloatContractionKernelInternal16x16<Index, LhsMapper, RhsMapper, OutputMapper, false, true>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n);
-    }
-  } else {
-    if (base_n + 63 < n_size) {
-      EigenFloatContractionKernelInternal16x16<Index, LhsMapper, RhsMapper, OutputMapper, true, false>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n);
-    } else {
-      EigenFloatContractionKernelInternal16x16<Index, LhsMapper, RhsMapper, OutputMapper, true, true>(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n);
-    }
-  }
-}
-
-
-template<typename Indices, typename LeftArgType, typename RightArgType>
-struct TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgType>, GpuDevice> :
-    public TensorContractionEvaluatorBase<TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgType>, GpuDevice> > {
-
-  typedef GpuDevice Device;
-
-  typedef TensorEvaluator<const TensorContractionOp<Indices, LeftArgType, RightArgType>, Device> Self;
-  typedef TensorContractionEvaluatorBase<Self> Base;
-
-  typedef TensorContractionOp<Indices, LeftArgType, RightArgType> XprType;
-  typedef typename internal::remove_const<typename XprType::Scalar>::type Scalar;
-  typedef typename XprType::Index Index;
-  typedef typename XprType::CoeffReturnType CoeffReturnType;
-  typedef typename PacketType<CoeffReturnType, GpuDevice>::type PacketReturnType;
-
-  enum {
-    Layout = TensorEvaluator<LeftArgType, Device>::Layout,
-  };
-
-  // Most of the code is assuming that both input tensors are ColMajor. If the
-  // inputs are RowMajor, we will "cheat" by swapping the LHS and RHS:
-  // If we want to compute A * B = C, where A is LHS and B is RHS, the code
-  // will pretend B is LHS and A is RHS.
-  typedef typename internal::conditional<
-    static_cast<int>(Layout) == static_cast<int>(ColMajor), LeftArgType, RightArgType>::type EvalLeftArgType;
-  typedef typename internal::conditional<
-    static_cast<int>(Layout) == static_cast<int>(ColMajor), RightArgType, LeftArgType>::type EvalRightArgType;
-
-  static const int LDims =
-      internal::array_size<typename TensorEvaluator<EvalLeftArgType, Device>::Dimensions>::value;
-  static const int RDims =
-      internal::array_size<typename TensorEvaluator<EvalRightArgType, Device>::Dimensions>::value;
-  static const int ContractDims = internal::array_size<Indices>::value;
-
-  typedef array<Index, LDims> left_dim_mapper_t;
-  typedef array<Index, RDims> right_dim_mapper_t;
-
-  typedef array<Index, ContractDims> contract_t;
-  typedef array<Index, LDims - ContractDims> left_nocontract_t;
-  typedef array<Index, RDims - ContractDims> right_nocontract_t;
-
-  static const int NumDims = LDims + RDims - 2 * ContractDims;
-
-  typedef DSizes<Index, NumDims> Dimensions;
-
-  // typedefs needed in evalTo
-  typedef typename internal::remove_const<typename EvalLeftArgType::Scalar>::type LhsScalar;
-  typedef typename internal::remove_const<typename EvalRightArgType::Scalar>::type RhsScalar;
-
-  typedef TensorEvaluator<EvalLeftArgType, Device> LeftEvaluator;
-  typedef TensorEvaluator<EvalRightArgType, Device> RightEvaluator;
-
-  typedef typename LeftEvaluator::Dimensions LeftDimensions;
-  typedef typename RightEvaluator::Dimensions RightDimensions;
-
-  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) :
-      Base(op, device) {}
- 
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~TensorEvaluator() {}
-
-  // We need to redefine this method to make hipcc happy
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) {
-    this->m_leftImpl.evalSubExprsIfNeeded(NULL);
-    this->m_rightImpl.evalSubExprsIfNeeded(NULL);
-    if (data) {
-      evalTo(data);
-      return false;
-    } else {
-      this->m_result = static_cast<Scalar *>(this->m_device.allocate(this->dimensions().TotalSize() * sizeof(Scalar)));
-      evalTo(this->m_result);
-      return true;
-    }
-  }
-
-  void evalTo(Scalar* buffer) const {
-    if (this->m_lhs_inner_dim_contiguous) {
-      if (this->m_rhs_inner_dim_contiguous) {
-        if (this->m_rhs_inner_dim_reordered) {
-          evalTyped<true, true, true, Unaligned>(buffer);
-        }
-        else {
-          evalTyped<true, true, false, Unaligned>(buffer);
-        }
-      }
-      else {
-       if (this->m_rhs_inner_dim_reordered) {
-          evalTyped<true, false, true, Unaligned>(buffer);
-        }
-        else {
-          evalTyped<true, false, false, Unaligned>(buffer);
-        }
-      }
-    }
-    else {
-      if (this->m_rhs_inner_dim_contiguous) {
-        if (this->m_rhs_inner_dim_reordered) {
-          evalTyped<false, true, true, Unaligned>(buffer);
-        }
-        else {
-          evalTyped<false, true, false, Unaligned>(buffer);
-        }
-      }
-      else {
-       if (this->m_rhs_inner_dim_reordered) {
-          evalTyped<false, false, true, Unaligned>(buffer);
-        }
-        else {
-          evalTyped<false, false, false, Unaligned>(buffer);
-        }
-      }
-    }
-  }
-
-  template <typename LhsScalar, typename RhsScalar, typename Index, typename LhsMapper, typename RhsMapper, typename OutputMapper> struct LaunchKernels {
-    static void Run(const LhsMapper& lhs, const RhsMapper& rhs, const OutputMapper& output, Index m, Index n, Index k, const GpuDevice& device) {
-    const Index m_blocks = (m + 63) / 64;
-    const Index n_blocks = (n + 63) / 64;
-    const dim3 num_blocks(m_blocks, n_blocks, 1);
-    const dim3 block_size(8, 8, 8);
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenContractionKernel<Scalar, Index, LhsMapper, RhsMapper, OutputMapper>),
-                    dim3(num_blocks), dim3(block_size), 0, device.stream(), lhs, rhs, output, m, n, k);
-    }
-  };
-
-  template <typename Index, typename LhsMapper, typename RhsMapper, typename OutputMapper> struct LaunchKernels<float, float, Index, LhsMapper, RhsMapper, OutputMapper> {
-    static void Run(const LhsMapper& lhs, const RhsMapper& rhs, const OutputMapper& output, Index m, Index n, Index k, const GpuDevice& device) {
-      if (m < 768 || n < 768) {
-        const Index m_blocks = (m + 63) / 64;
-        const Index n_blocks = (n + 63) / 64;
-        const dim3 num_blocks(m_blocks, n_blocks, 1);
-        const dim3 block_size(16, 16, 1);
-        hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenFloatContractionKernel16x16<Index, LhsMapper, RhsMapper, OutputMapper>),
-                        dim3(num_blocks), dim3(block_size), 0, device.stream(), lhs, rhs, output, m, n, k);
-      } else {
-        const Index m_blocks = (m + 127) / 128;
-        const Index n_blocks = (n + 63) / 64;
-        const dim3 num_blocks(m_blocks, n_blocks, 1);
-        const dim3 block_size(8, 32, 1);
-        hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenFloatContractionKernel<Index, LhsMapper, RhsMapper, OutputMapper>),
-                        dim3(num_blocks), dim3(block_size), 0, device.stream(), lhs, rhs, output, m, n, k);
-      }
-    }
-  };
-
-  template <bool lhs_inner_dim_contiguous, bool rhs_inner_dim_contiguous, bool rhs_inner_dim_reordered, int Alignment>
-  void evalTyped(Scalar* buffer) const {
-    // columns in left side, rows in right side
-    const Index k = this->m_k_size;
-    EIGEN_UNUSED_VARIABLE(k)
-
-    // rows in left side
-    const Index m = this->m_i_size;
-
-    // columns in right side
-    const Index n = this->m_j_size;
-
-    // zero out the result buffer (which must be of size at least m * n * sizeof(Scalar)
-    this->m_device.memset(buffer, 0, m * n * sizeof(Scalar));
-
-    typedef internal::TensorContractionInputMapper<LhsScalar, Index, internal::Lhs,
-                                                   LeftEvaluator, left_nocontract_t,
-                                                   contract_t, 4,
-                                                   lhs_inner_dim_contiguous,
-                                                   false, Unaligned> LhsMapper;
-
-    typedef internal::TensorContractionInputMapper<RhsScalar, Index, internal::Rhs,
-                                                   RightEvaluator, right_nocontract_t,
-                                                   contract_t, 4,
-                                                   rhs_inner_dim_contiguous,
-                                                   rhs_inner_dim_reordered, Unaligned> RhsMapper;
-
-    typedef internal::blas_data_mapper<Scalar, Index, ColMajor> OutputMapper;
-
-
-    // initialize data mappers
-    LhsMapper lhs(this->m_leftImpl, this->m_left_nocontract_strides, this->m_i_strides,
-                  this->m_left_contracting_strides, this->m_k_strides);
-
-    RhsMapper rhs(this->m_rightImpl, this->m_right_nocontract_strides, this->m_j_strides,
-                  this->m_right_contracting_strides, this->m_k_strides);
-
-    OutputMapper output(buffer, m);
-
-    setHipSharedMemConfig(hipSharedMemBankSizeEightByte);
-    LaunchKernels<LhsScalar, RhsScalar, Index, LhsMapper, RhsMapper, OutputMapper>::Run(lhs, rhs, output,  m, n, k, this->m_device);
-  }
-};
-
-} // end namespace Eigen
-
-#endif // EIGEN_USE_GPU and EIGEN_HIPCC
-#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_HIP_H
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorConvolutionHip.h b/unsupported/Eigen/CXX11/src/Tensor/TensorConvolutionHip.h
deleted file mode 100644
index ba99710..0000000
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorConvolutionHip.h
+++ /dev/null
@@ -1,1119 +0,0 @@
-//#include "hip/hip_runtime.h"
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H
-#define EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H
-
-namespace Eigen {
-
-/** \class TensorConvolution
-  * \ingroup CXX11_Tensor_Module
-  *
-  * \brief Tensor convolution class.
-  *
-  *
-  */
-namespace internal {
-
-template <typename Index, typename InputDims, int NumKernelDims, int Layout>
-class IndexMapper {
- public:
-  IndexMapper(const InputDims& input_dims, const array<Index, NumKernelDims>& kernel_dims,
-              const array<Index, NumKernelDims>& indices) {
-
-    array<Index, NumDims> dimensions = input_dims;
-    for (int i = 0; i < NumKernelDims; ++i) {
-      const Index index = indices[i];
-      const Index input_dim = input_dims[index];
-      const Index kernel_dim = kernel_dims[i];
-      const Index result_dim = input_dim - kernel_dim + 1;
-      dimensions[index] = result_dim;
-    }
-
-    array<Index, NumDims> inputStrides;
-    array<Index, NumDims> outputStrides;
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      inputStrides[0] = 1;
-      outputStrides[0] = 1;
-      for (int i = 1; i < NumDims; ++i) {
-        inputStrides[i] = inputStrides[i-1] * input_dims[i-1];
-        outputStrides[i] = outputStrides[i-1] * dimensions[i-1];
-      }
-    } else {
-      inputStrides[NumDims - 1] = 1;
-      outputStrides[NumDims - 1] = 1;
-      for (int i = static_cast<int>(NumDims) - 2; i >= 0; --i) {
-        inputStrides[i] = inputStrides[i + 1] * input_dims[i + 1];
-        outputStrides[i] = outputStrides[i + 1] * dimensions[i + 1];
-      }
-    }
-
-    array<Index, NumDims> hipInputDimensions;
-    array<Index, NumDims> hipOutputDimensions;
-    array<Index, NumDims> tmp = dimensions;
-    array<Index, NumDims> ordering;
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    for (int i = 0; i < NumKernelDims; ++i) {
-      const Index index = i + offset;
-      ordering[index] = indices[i];
-      tmp[indices[i]] = -1;
-      hipInputDimensions[index] = input_dims[indices[i]];
-      hipOutputDimensions[index] = dimensions[indices[i]];
-    }
-
-    int written = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                      ? NumKernelDims
-                      : 0;
-    for (int i = 0; i < NumDims; ++i) {
-      if (tmp[i] >= 0) {
-        ordering[written] = i;
-        hipInputDimensions[written] = input_dims[i];
-        hipOutputDimensions[written] = dimensions[i];
-        ++written;
-      }
-    }
-
-    for (int i = 0; i < NumDims; ++i) {
-      m_inputStrides[i] = inputStrides[ordering[i]];
-      m_outputStrides[i] = outputStrides[ordering[i]];
-    }
-
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int i = 0; i < NumDims; ++i) {
-        if (i > NumKernelDims) {
-          m_hipInputStrides[i] =
-              m_hipInputStrides[i - 1] * hipInputDimensions[i - 1];
-          m_hipOutputStrides[i] =
-              m_hipOutputStrides[i - 1] * hipOutputDimensions[i - 1];
-        } else {
-          m_hipInputStrides[i] = 1;
-          m_hipOutputStrides[i] = 1;
-        }
-      }
-    } else {
-      for (int i = NumDims - 1; i >= 0; --i) {
-        if (i + 1 < offset) {
-          m_hipInputStrides[i] =
-              m_hipInputStrides[i + 1] * hipInputDimensions[i + 1];
-          m_hipOutputStrides[i] =
-              m_hipOutputStrides[i + 1] * hipOutputDimensions[i + 1];
-        } else {
-          m_hipInputStrides[i] = 1;
-          m_hipOutputStrides[i] = 1;
-        }
-      }
-    }
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipInputPlaneToTensorInputOffset(Index p) const {
-    Index inputIndex = 0;
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int d = NumDims - 1; d > NumKernelDims; --d) {
-        const Index idx = p / m_hipInputStrides[d];
-        inputIndex += idx * m_inputStrides[d];
-        p -= idx * m_hipInputStrides[d];
-      }
-      inputIndex += p * m_inputStrides[NumKernelDims];
-    } else {
-      std::ptrdiff_t limit = 0;
-      if (NumKernelDims < NumDims) {
-        limit = NumDims - NumKernelDims - 1;
-      }
-      for (int d = 0; d < limit; ++d) {
-        const Index idx = p / m_hipInputStrides[d];
-        inputIndex += idx * m_inputStrides[d];
-        p -= idx * m_hipInputStrides[d];
-      }
-      inputIndex += p * m_inputStrides[limit];
-    }
-    return inputIndex;
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipOutputPlaneToTensorOutputOffset(Index p) const {
-    Index outputIndex = 0;
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int d = NumDims - 1; d > NumKernelDims; --d) {
-        const Index idx = p / m_hipOutputStrides[d];
-        outputIndex += idx * m_outputStrides[d];
-        p -= idx * m_hipOutputStrides[d];
-      }
-      outputIndex += p * m_outputStrides[NumKernelDims];
-    } else {
-      std::ptrdiff_t limit = 0;
-      if (NumKernelDims < NumDims) {
-        limit = NumDims - NumKernelDims - 1;
-      }
-      for (int d = 0; d < limit; ++d) {
-        const Index idx = p / m_hipOutputStrides[d];
-        outputIndex += idx * m_outputStrides[d];
-        p -= idx * m_hipOutputStrides[d];
-      }
-      outputIndex += p * m_outputStrides[limit];
-    }
-    return outputIndex;
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipInputKernelToTensorInputOffset(Index i) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_inputStrides[offset];
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipOutputKernelToTensorOutputOffset(Index i) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_outputStrides[offset];
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipInputKernelToTensorInputOffset(Index i, Index j) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_inputStrides[offset] + j * m_inputStrides[offset + 1];
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipOutputKernelToTensorOutputOffset(Index i, Index j) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_outputStrides[offset] + j * m_outputStrides[offset + 1];
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipInputKernelToTensorInputOffset(Index i, Index j, Index k) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_inputStrides[offset] + j * m_inputStrides[offset + 1] +
-           k * m_inputStrides[offset + 2];
-  }
-
-  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapHipOutputKernelToTensorOutputOffset(Index i, Index j, Index k) const {
-    const size_t offset = static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                              ? 0
-                              : NumDims - NumKernelDims;
-    return i * m_outputStrides[offset] + j * m_outputStrides[offset + 1] +
-           k * m_outputStrides[offset + 2];
-  }
-
- private:
-  static const int NumDims = internal::array_size<InputDims>::value;
-  array<Index, NumDims> m_inputStrides;
-  array<Index, NumDims> m_outputStrides;
-  array<Index, NumDims> m_hipInputStrides;
-  array<Index, NumDims> m_hipOutputStrides;
-};
-
-
-
-template<typename Dimensions, typename InputXprType, typename KernelXprType>
-struct traits<TensorConvolutionOp<Dimensions, InputXprType, KernelXprType> >
-{
-  // Type promotion to handle the case where the types of the lhs and the rhs are different.
-  typedef typename promote_storage_type<typename InputXprType::Scalar,
-                                        typename KernelXprType::Scalar>::ret Scalar;
-  typedef typename promote_storage_type<typename traits<InputXprType>::StorageKind,
-                                        typename traits<KernelXprType>::StorageKind>::ret StorageKind;
-  typedef typename promote_index_type<typename traits<InputXprType>::Index,
-                                      typename traits<KernelXprType>::Index>::type Index;
-  typedef typename InputXprType::Nested LhsNested;
-  typedef typename KernelXprType::Nested RhsNested;
-  typedef typename remove_reference<LhsNested>::type _LhsNested;
-  typedef typename remove_reference<RhsNested>::type _RhsNested;
-  static const int NumDimensions = traits<InputXprType>::NumDimensions;
-  static const int Layout = traits<InputXprType>::Layout;
-
-  enum {
-    Flags = 0
-  };
-};
-
-template<typename Dimensions, typename InputXprType, typename KernelXprType>
-struct eval<TensorConvolutionOp<Dimensions, InputXprType, KernelXprType>, Eigen::Dense>
-{
-  typedef const TensorConvolutionOp<Dimensions, InputXprType, KernelXprType>& type;
-};
-
-template<typename Dimensions, typename InputXprType, typename KernelXprType>
-struct nested<TensorConvolutionOp<Dimensions, InputXprType, KernelXprType>, 1, typename eval<TensorConvolutionOp<Dimensions, InputXprType, KernelXprType> >::type>
-{
-  typedef TensorConvolutionOp<Dimensions, InputXprType, KernelXprType> type;
-};
-
-}  // end namespace internal
-
-
-
-template<typename Indices, typename InputXprType, typename KernelXprType>
-class TensorConvolutionOp : public TensorBase<TensorConvolutionOp<Indices, InputXprType, KernelXprType>, ReadOnlyAccessors>
-{
-  public:
-  typedef typename Eigen::internal::traits<TensorConvolutionOp>::Scalar Scalar;
-  typedef typename Eigen::NumTraits<Scalar>::Real RealScalar;
-  typedef typename internal::promote_storage_type<typename InputXprType::CoeffReturnType,
-                                                  typename KernelXprType::CoeffReturnType>::ret CoeffReturnType;
-  typedef typename Eigen::internal::nested<TensorConvolutionOp>::type Nested;
-  typedef typename Eigen::internal::traits<TensorConvolutionOp>::StorageKind StorageKind;
-  typedef typename Eigen::internal::traits<TensorConvolutionOp>::Index Index;
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorConvolutionOp(const InputXprType& input, const KernelXprType& kernel, const Indices& dims)
-      : m_input_xpr(input), m_kernel_xpr(kernel), m_indices(dims) {}
-
-    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
-    const Indices& indices() const { return m_indices; }
-
-    /** \returns the nested expressions */
-    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
-    const typename internal::remove_all<typename InputXprType::Nested>::type&
-    inputExpression() const { return m_input_xpr; }
-
-    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
-    const typename internal::remove_all<typename KernelXprType::Nested>::type&
-    kernelExpression() const { return m_kernel_xpr; }
-
-  protected:
-    typename InputXprType::Nested m_input_xpr;
-    typename KernelXprType::Nested m_kernel_xpr;
-    const Indices m_indices;
-};
-
-
-template<typename Indices, typename InputArgType, typename KernelArgType, typename Device>
-struct TensorEvaluator<const TensorConvolutionOp<Indices, InputArgType, KernelArgType>, Device>
-{
-  typedef TensorConvolutionOp<Indices, InputArgType, KernelArgType> XprType;
-
-  static const int NumDims = internal::array_size<typename TensorEvaluator<InputArgType, Device>::Dimensions>::value;
-  static const int NumKernelDims = internal::array_size<Indices>::value;
-  typedef typename XprType::Index Index;
-  typedef DSizes<Index, NumDims> Dimensions;
-
-  typedef typename XprType::Scalar Scalar;
-  typedef typename XprType::CoeffReturnType CoeffReturnType;
-  typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType;
-  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
-
-  enum {
-    IsAligned = TensorEvaluator<InputArgType, Device>::IsAligned & TensorEvaluator<KernelArgType, Device>::IsAligned,
-    PacketAccess = TensorEvaluator<InputArgType, Device>::PacketAccess & TensorEvaluator<KernelArgType, Device>::PacketAccess,
-    Layout = TensorEvaluator<InputArgType, Device>::Layout,
-    CoordAccess = false,  // to be implemented
-    RawAccess = false
-  };
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device)
-      : m_inputImpl(op.inputExpression(), device), m_kernelImpl(op.kernelExpression(), device), m_kernelArg(op.kernelExpression()), m_kernel(NULL), m_local_kernel(false), m_device(device)
-  {
-    EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<InputArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<KernelArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
-
-    const typename TensorEvaluator<InputArgType, Device>::Dimensions& input_dims = m_inputImpl.dimensions();
-    const typename TensorEvaluator<KernelArgType, Device>::Dimensions& kernel_dims = m_kernelImpl.dimensions();
-
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      m_inputStride[0] = 1;
-      for (int i = 1; i < NumDims; ++i) {
-        m_inputStride[i] = m_inputStride[i - 1] * input_dims[i - 1];
-      }
-    } else {
-      m_inputStride[NumDims - 1] = 1;
-      for (int i = NumDims - 2; i >= 0; --i) {
-        m_inputStride[i] = m_inputStride[i + 1] * input_dims[i + 1];
-      }
-    }
-
-    m_dimensions = m_inputImpl.dimensions();
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int i = 0; i < NumKernelDims; ++i) {
-        const Index index = op.indices()[i];
-        const Index input_dim = input_dims[index];
-        const Index kernel_dim = kernel_dims[i];
-        const Index result_dim = input_dim - kernel_dim + 1;
-        m_dimensions[index] = result_dim;
-        if (i > 0) {
-          m_kernelStride[i] = m_kernelStride[i - 1] * kernel_dims[i - 1];
-        } else {
-          m_kernelStride[0] = 1;
-        }
-        m_indexStride[i] = m_inputStride[index];
-      }
-
-      m_outputStride[0] = 1;
-      for (int i = 1; i < NumDims; ++i) {
-        m_outputStride[i] = m_outputStride[i - 1] * m_dimensions[i - 1];
-      }
-    } else {
-      for (int i = NumKernelDims - 1; i >= 0; --i) {
-        const Index index = op.indices()[i];
-        const Index input_dim = input_dims[index];
-        const Index kernel_dim = kernel_dims[i];
-        const Index result_dim = input_dim - kernel_dim + 1;
-        m_dimensions[index] = result_dim;
-        if (i < NumKernelDims - 1) {
-          m_kernelStride[i] = m_kernelStride[i + 1] * kernel_dims[i + 1];
-        } else {
-          m_kernelStride[NumKernelDims - 1] = 1;
-        }
-        m_indexStride[i] = m_inputStride[index];
-      }
-
-      m_outputStride[NumDims - 1] = 1;
-      for (int i = NumDims - 2; i >= 0; --i) {
-        m_outputStride[i] = m_outputStride[i + 1] * m_dimensions[i + 1];
-      }
-    }
-  }
- 
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~TensorEvaluator() {}
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) {
-    m_inputImpl.evalSubExprsIfNeeded(NULL);
-    preloadKernel();
-    return true;
-  }
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() {
-    m_inputImpl.cleanup();
-    if (m_local_kernel) {
-      m_device.deallocate((void*)m_kernel);
-      m_local_kernel = false;
-    }
-    m_kernel = NULL;
-  }
-
-  void evalTo(typename XprType::Scalar* buffer) {
-    evalSubExprsIfNeeded(NULL);
-    for (int i = 0; i < dimensions().TotalSize(); ++i) {
-      buffer[i] += coeff(i);
-    }
-    cleanup();
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
-  {
-    CoeffReturnType result = CoeffReturnType(0);
-    convolve(firstInput(index), 0, NumKernelDims-1, result);
-    return result;
-  }
-
-  template<int LoadMode>
-  EIGEN_DEVICE_FUNC PacketReturnType packet(const Index index) const
-  {
-    Index indices[2] = {index, index+PacketSize-1};
-    Index startInputs[2] = {0, 0};
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int i = NumDims - 1; i > 0; --i) {
-        const Index idx0 = indices[0] / m_outputStride[i];
-        const Index idx1 = indices[1] / m_outputStride[i];
-        startInputs[0] += idx0 * m_inputStride[i];
-        startInputs[1] += idx1 * m_inputStride[i];
-        indices[0] -= idx0 * m_outputStride[i];
-        indices[1] -= idx1 * m_outputStride[i];
-      }
-    } else {
-      for (int i = 0; i < NumDims - 1; ++i) {
-        const Index idx0 = indices[0] / m_outputStride[i];
-        const Index idx1 = indices[1] / m_outputStride[i];
-        startInputs[0] += idx0 * m_inputStride[i];
-        startInputs[1] += idx1 * m_inputStride[i];
-        indices[0] -= idx0 * m_outputStride[i];
-        indices[1] -= idx1 * m_outputStride[i];
-      }
-    }
-    startInputs[0] += indices[0];
-    startInputs[1] += indices[1];
-
-    if (startInputs[1]-startInputs[0] == PacketSize-1) {
-      PacketReturnType result = internal::pset1<PacketReturnType>(0);
-      convolvePacket(startInputs[0], 0, NumKernelDims-1, result);
-      return result;
-    } else {
-      EIGEN_ALIGN_MAX Scalar data[PacketSize];
-      data[0] = Scalar(0);
-      convolve(startInputs[0], 0, NumKernelDims-1, data[0]);
-      for (int i = 1; i < PacketSize-1; ++i) {
-        data[i] = Scalar(0);
-        convolve(firstInput(index+i), 0, NumKernelDims-1, data[i]);
-      }
-      data[PacketSize-1] = Scalar(0);
-      convolve(startInputs[1], 0, NumKernelDims-1, data[PacketSize-1]);
-      return internal::pload<PacketReturnType>(data);
-    }
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
-  costPerCoeff(bool vectorized) const {
-    const double kernel_size = m_kernelImpl.dimensions().TotalSize();
-    // We ignore the use of fused multiply-add.
-    const double convolve_compute_cost =
-        TensorOpCost::AddCost<Scalar>() + TensorOpCost::MulCost<Scalar>();
-    const double firstIndex_compute_cost =
-        NumDims *
-        (2 * TensorOpCost::AddCost<Index>() + 2 * TensorOpCost::MulCost<Index>() +
-         TensorOpCost::DivCost<Index>());
-    return TensorOpCost(0, 0, firstIndex_compute_cost, vectorized, PacketSize) +
-           kernel_size * (m_inputImpl.costPerCoeff(vectorized) +
-                          m_kernelImpl.costPerCoeff(vectorized) +
-                          TensorOpCost(0, 0, convolve_compute_cost, vectorized,
-                                       PacketSize));
-  }
-
-  EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; }
-
- private:
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index firstInput(Index index) const {
-    Index startInput = 0;
-    if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) {
-      for (int i = NumDims - 1; i > 0; --i) {
-        const Index idx = index / m_outputStride[i];
-        startInput += idx * m_inputStride[i];
-        index -= idx * m_outputStride[i];
-      }
-    } else {
-      for (int i = 0; i < NumDims - 1; ++i) {
-        const Index idx = index / m_outputStride[i];
-        startInput += idx * m_inputStride[i];
-        index -= idx * m_outputStride[i];
-      }
-    }
-    startInput += index;
-    return startInput;
-  }
-
-  EIGEN_DEVICE_FUNC void convolve(Index firstIndex, Index firstKernel, int DimIndex, CoeffReturnType& accum) const {
-    for (int j = 0; j < m_kernelImpl.dimensions()[DimIndex]; ++j) {
-      const Index input = firstIndex + j * m_indexStride[DimIndex];
-      const Index kernel = firstKernel + j * m_kernelStride[DimIndex];
-      if (DimIndex > 0) {
-        convolve(input, kernel, DimIndex-1, accum);
-      } else {
-        accum += m_inputImpl.coeff(input) * m_kernel[kernel];
-      }
-    }
-  }
-
-  template <typename Packet>
-  EIGEN_DEVICE_FUNC void convolvePacket(Index firstIndex, Index firstKernel, int DimIndex, Packet& accum) const {
-    for (int j = 0; j < m_kernelImpl.dimensions()[DimIndex]; ++j) {
-      const Index input = firstIndex + j * m_indexStride[DimIndex];
-      const Index kernel = firstKernel + j * m_kernelStride[DimIndex];
-      if (DimIndex > 0) {
-        convolvePacket(input, kernel, DimIndex-1, accum);
-      } else {
-        accum = internal::pmadd<Packet>(m_inputImpl.template packet<Unaligned>(input), internal::pset1<Packet>(m_kernel[kernel]), accum);
-      }
-    }
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void preloadKernel() {
-    // Don't make a local copy of the kernel unless we have to (i.e. it's an
-    // expression that needs to be evaluated)
-    const Scalar* in_place = m_kernelImpl.data();
-    if (in_place) {
-      m_kernel = in_place;
-      m_local_kernel = false;
-    } else {
-      size_t kernel_sz = m_kernelImpl.dimensions().TotalSize() * sizeof(Scalar);
-      Scalar* local = (Scalar*)m_device.allocate(kernel_sz);
-      typedef TensorEvalToOp<const KernelArgType> EvalTo;
-      EvalTo evalToTmp(local, m_kernelArg);
-      const bool PacketAccess = internal::IsVectorizable<Device, KernelArgType>::value;
-      internal::TensorExecutor<const EvalTo, Device, PacketAccess>::run(evalToTmp, m_device);
-
-      m_kernel = local;
-      m_local_kernel = true;
-    }
-  }
-
-  array<Index, NumDims> m_inputStride;
-  array<Index, NumDims> m_outputStride;
-
-  array<Index, NumKernelDims> m_indexStride;
-  array<Index, NumKernelDims> m_kernelStride;
-  TensorEvaluator<InputArgType, Device> m_inputImpl;
-  TensorEvaluator<KernelArgType, Device> m_kernelImpl;
-  Dimensions m_dimensions;
-
-  KernelArgType m_kernelArg;
-  const Scalar* m_kernel;
-  bool m_local_kernel;
-  const Device& m_device;
-};
-
-
-
-
-// Use an optimized implementation of the evaluation code for GPUs whenever possible.
-#if defined(EIGEN_USE_GPU) && defined(EIGEN_HIPCC)
-
-template <int StaticKernelSize>
-struct GetKernelSize {
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int operator() (const int /*kernelSize*/) const {
-    return StaticKernelSize;
-  }
-};
-template <>
-struct GetKernelSize<Dynamic> {
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int operator() (const int kernelSize) const {
-    return kernelSize;
-  }
-};
-
-template <typename InputEvaluator, typename Index, typename InputDims,
-          int StaticKernelSize>
-__global__ void EigenConvolutionKernel1D(
-    InputEvaluator eval,
-    const internal::IndexMapper<Index, InputDims, 1, InputEvaluator::Layout>
-        indexMapper,
-    const float* __restrict kernel, const int numPlanes, const int numX,
-    const int maxX, const int kernelSize, float* buffer) {
-  HIP_DYNAMIC_SHARED( float, s)
-
-  const int first_x = hipBlockIdx_x * maxX;
-  const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1;
-  const int num_x_input = last_x - first_x + GetKernelSize<StaticKernelSize>()(kernelSize);
-  const int num_x_output = last_x - first_x + 1;
-
-  const int first_plane = hipBlockIdx_y * hipBlockDim_y;
-  const int plane_stride = hipBlockDim_y * hipGridDim_y;
-
-  for (int p = first_plane + hipThreadIdx_y; p < numPlanes; p += plane_stride) {
-    // Load inputs to shared memory
-    const int plane_input_offset = indexMapper.mapHipInputPlaneToTensorInputOffset(p);
-    const int plane_kernel_offset = hipThreadIdx_y * num_x_input;
-    #pragma unroll
-    for (int i = hipThreadIdx_x; i < num_x_input; i += hipBlockDim_x) {
-      const int tensor_index = plane_input_offset + indexMapper.mapHipInputKernelToTensorInputOffset(i+first_x);
-      s[i + plane_kernel_offset] = eval.coeff(tensor_index);
-    }
-
-    __syncthreads();
-
-    // Compute the convolution
-    const int plane_output_offset = indexMapper.mapHipOutputPlaneToTensorOutputOffset(p);
-
-    #pragma unroll
-    for (int i = hipThreadIdx_x; i < num_x_output; i += hipBlockDim_x) {
-      const int kernel_offset = plane_kernel_offset + i;
-      float result = 0.0f;
-      #pragma unroll
-      for (int k = 0; k < GetKernelSize<StaticKernelSize>()(kernelSize); ++k) {
-        result += s[k + kernel_offset] * kernel[k];
-      }
-      const int tensor_index = plane_output_offset + indexMapper.mapHipOutputKernelToTensorOutputOffset(i+first_x);
-      buffer[tensor_index] = result;
-    }
-    __syncthreads();
-  }
-};
-
-template <typename InputEvaluator, typename Index, typename InputDims,
-          int StaticKernelSizeX, int StaticKernelSizeY>
-__global__ void EigenConvolutionKernel2D(
-    InputEvaluator eval,
-    const internal::IndexMapper<Index, InputDims, 2, InputEvaluator::Layout>
-        indexMapper,
-    const float* __restrict kernel, const int numPlanes, const int numX,
-    const int maxX, const int numY, const int maxY, const int kernelSizeX,
-    const int kernelSizeY, float* buffer) {
-  HIP_DYNAMIC_SHARED( float, s)
-
-  const int first_x = hipBlockIdx_x * maxX;
-  const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1;
-  const int num_x_input = last_x - first_x + GetKernelSize<StaticKernelSizeX>()(kernelSizeX);
-  const int num_x_output = last_x - first_x + 1;
-
-  const int first_y = hipBlockIdx_y * maxY;
-  const int last_y = (first_y + maxY < numY ? first_y + maxY : numY) - 1;
-  const int num_y_input = last_y - first_y + GetKernelSize<StaticKernelSizeY>()(kernelSizeY);
-  const int num_y_output = last_y - first_y + 1;
-
-  const int first_plane = hipBlockIdx_z * hipBlockDim_z;
-  const int plane_stride = hipBlockDim_z * hipGridDim_z;
-
-  for (int p = first_plane + hipThreadIdx_z; p < numPlanes; p += plane_stride) {
-
-    const int plane_input_offset = indexMapper.mapHipInputPlaneToTensorInputOffset(p);
-    const int plane_kernel_offset = hipThreadIdx_z * num_y_input;
-
-    // Load inputs to shared memory
-    #pragma unroll
-    for (int j = hipThreadIdx_y; j < num_y_input; j += hipBlockDim_y) {
-      const int input_offset = num_x_input * (j + plane_kernel_offset);
-      #pragma unroll
-      for (int i = hipThreadIdx_x; i < num_x_input; i += hipBlockDim_x) {
-        const int tensor_index = plane_input_offset + indexMapper.mapHipInputKernelToTensorInputOffset(i+first_x, j+first_y);
-        s[i + input_offset] = eval.coeff(tensor_index);
-      }
-    }
-
-    __syncthreads();
-
-    // Convolution
-    const int plane_output_offset = indexMapper.mapHipOutputPlaneToTensorOutputOffset(p);
-
-    #pragma unroll
-    for (int j = hipThreadIdx_y; j < num_y_output; j += hipBlockDim_y) {
-      #pragma unroll
-      for (int i = hipThreadIdx_x; i < num_x_output; i += hipBlockDim_x) {
-        float result = 0.0f;
-        #pragma unroll
-        for (int l = 0; l < GetKernelSize<StaticKernelSizeY>()(kernelSizeY); ++l) {
-          const int kernel_offset = kernelSizeX * l;
-          const int input_offset = i + num_x_input * (j + l + plane_kernel_offset);
-          #pragma unroll
-          for (int k = 0; k < GetKernelSize<StaticKernelSizeX>()(kernelSizeX); ++k) {
-            result += s[k + input_offset] * kernel[k + kernel_offset];
-          }
-        }
-        const int tensor_index = plane_output_offset + indexMapper.mapHipOutputKernelToTensorOutputOffset(i+first_x, j+first_y);
-        buffer[tensor_index] = result;
-      }
-    }
-
-    __syncthreads();
-  }
-};
-
-template <typename InputEvaluator, typename Index, typename InputDims>
-__global__ void EigenConvolutionKernel3D( 
-    InputEvaluator eval,
-    const internal::IndexMapper<Index, InputDims, 3, InputEvaluator::Layout>
-        indexMapper,
-    const float* __restrict kernel, const size_t numPlanes, const size_t numX,
-    const size_t maxX, const size_t numY, const size_t maxY, const size_t numZ,
-    const size_t maxZ, const size_t kernelSizeX, const size_t kernelSizeY,
-    const size_t kernelSizeZ, float* buffer) {
-  HIP_DYNAMIC_SHARED( float, s)
-
-  // Load inputs to shared memory
-  const int first_x = hipBlockIdx_x * maxX;
-  const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1;
-  const int num_x_input = last_x - first_x + kernelSizeX;
-
-  const int first_y = hipBlockIdx_y * maxY;
-  const int last_y = (first_y + maxY < numY ? first_y + maxY : numY) - 1;
-  const int num_y_input = last_y - first_y + kernelSizeY;
-
-  const int first_z = hipBlockIdx_z * maxZ;
-  const int last_z = (first_z + maxZ < numZ ? first_z + maxZ : numZ) - 1;
-  const int num_z_input = last_z - first_z + kernelSizeZ;
-
-  for (int p = 0; p < numPlanes; ++p) {
-
-    const int plane_input_offset = indexMapper.mapHipInputPlaneToTensorInputOffset(p);
-    const int plane_kernel_offset = 0;
-
-    for (int k = hipThreadIdx_z; k < num_z_input; k += hipBlockDim_z) {
-      for (int j = hipThreadIdx_y; j < num_y_input; j += hipBlockDim_y) {
-        for (int i = hipThreadIdx_x; i < num_x_input; i += hipBlockDim_x) {
-          const int tensor_index = plane_input_offset + indexMapper.mapHipInputKernelToTensorInputOffset(i+first_x, j+first_y, k+first_z);
-          s[i + num_x_input * (j + num_y_input * (k + plane_kernel_offset))] = eval.coeff(tensor_index);
-        }
-      }
-    }
-
-    __syncthreads();
-
-    // Convolution
-    const int num_z_output = last_z - first_z + 1;
-    const int num_y_output = last_y - first_y + 1;
-    const int num_x_output = last_x - first_x + 1;
-    const int plane_output_offset = indexMapper.mapHipOutputPlaneToTensorOutputOffset(p);
-
-    for (int k = hipThreadIdx_z; k < num_z_output; k += hipBlockDim_z) {
-      for (int j = hipThreadIdx_y; j < num_y_output; j += hipBlockDim_y) {
-        for (int i = hipThreadIdx_x; i < num_x_output; i += hipBlockDim_x) {
-          float result = 0.0f;
-          for (int n = 0; n < kernelSizeZ; ++n) {
-            for (int m = 0; m < kernelSizeY; ++m) {
-              for (int l = 0; l < kernelSizeX; ++l) {
-                result += s[i + l + num_x_input * (j + m + num_y_input * (k + n + plane_kernel_offset))] * kernel[l + kernelSizeX * (m + kernelSizeY * n)];
-              }
-            }
-          }
-          const int tensor_index = plane_output_offset + indexMapper.mapHipOutputKernelToTensorOutputOffset(i+first_x, j+first_y, k+first_z);
-          buffer[tensor_index] = result;
-        }
-      }
-    }
-    __syncthreads();
-  }
-};
-
-
-
-template<typename Indices, typename InputArgType, typename KernelArgType>
-struct TensorEvaluator<const TensorConvolutionOp<Indices, InputArgType, KernelArgType>, GpuDevice>
-{
-  typedef TensorConvolutionOp<Indices, InputArgType, KernelArgType> XprType;
-
-  static const int NumDims =  internal::array_size<typename TensorEvaluator<InputArgType, GpuDevice>::Dimensions>::value;
-  static const int NumKernelDims = internal::array_size<Indices>::value;
-  typedef typename XprType::Index Index;
-  typedef DSizes<Index, NumDims> Dimensions;
-  typedef typename TensorEvaluator<KernelArgType, GpuDevice>::Dimensions KernelDimensions;
-
-  enum {
-    IsAligned = TensorEvaluator<InputArgType, GpuDevice>::IsAligned & TensorEvaluator<KernelArgType, GpuDevice>::IsAligned,
-    PacketAccess = false,
-    Layout = TensorEvaluator<InputArgType, GpuDevice>::Layout,
-    CoordAccess = false,  // to be implemented
-    RawAccess = false
-  };
-
-  EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const GpuDevice& device)
-      : m_inputImpl(op.inputExpression(), device), m_kernelArg(op.kernelExpression()), m_kernelImpl(op.kernelExpression(), device), m_indices(op.indices()), m_buf(NULL), m_kernel(NULL), m_local_kernel(false), m_device(device)
-  {
-    EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<InputArgType, GpuDevice>::Layout) == static_cast<int>(TensorEvaluator<KernelArgType, GpuDevice>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE);
-
-    const typename TensorEvaluator<InputArgType, GpuDevice>::Dimensions& input_dims = m_inputImpl.dimensions();
-    const typename TensorEvaluator<KernelArgType, GpuDevice>::Dimensions& kernel_dims = m_kernelImpl.dimensions();
-
-    m_dimensions = m_inputImpl.dimensions();
-    for (int i = 0; i < NumKernelDims; ++i) {
-      const Index index = op.indices()[i];
-      const Index input_dim = input_dims[index];
-      const Index kernel_dim = kernel_dims[i];
-      const Index result_dim = input_dim - kernel_dim + 1;
-      m_dimensions[index] = result_dim;
-    }
-  }
- 
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~TensorEvaluator() {}
-
-  typedef typename XprType::CoeffReturnType CoeffReturnType;
-  typedef typename PacketType<CoeffReturnType, GpuDevice>::type PacketReturnType;
-  typedef typename InputArgType::Scalar Scalar;
-  static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size;
-
-  EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_dimensions; }
-
-  EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) {
-    preloadKernel();
-    m_inputImpl.evalSubExprsIfNeeded(NULL);
-    if (data) {
-      executeEval(data);
-      return false;
-    } else {
-      m_buf = (Scalar*)m_device.allocate(dimensions().TotalSize() * sizeof(Scalar));
-      executeEval(m_buf);
-      return true;
-    }
-  }
-
-  EIGEN_STRONG_INLINE void cleanup() {
-    m_inputImpl.cleanup();
-    if (m_buf) {
-      m_device.deallocate(m_buf);
-      m_buf = NULL;
-    }
-    if (m_local_kernel) {
-      m_device.deallocate((void*)m_kernel);
-      m_local_kernel = false;
-    }
-    m_kernel = NULL;
-  }
-
-  EIGEN_STRONG_INLINE void preloadKernel() {
-    // Don't make a local copy of the kernel unless we have to (i.e. it's an
-    // expression that needs to be evaluated)
-    const Scalar* in_place = m_kernelImpl.data();
-    if (in_place) {
-      m_kernel = in_place;
-      m_local_kernel = false;
-    } else {
-      size_t kernel_sz = m_kernelImpl.dimensions().TotalSize() * sizeof(Scalar);
-      Scalar* local = (Scalar*)m_device.allocate(kernel_sz);
-      typedef TensorEvalToOp<const KernelArgType> EvalTo;
-      EvalTo evalToTmp(local, m_kernelArg);
-      const bool PacketAccess = internal::IsVectorizable<GpuDevice, KernelArgType>::value;
-      internal::TensorExecutor<const EvalTo, GpuDevice, PacketAccess>::run(evalToTmp, m_device);
-
-      m_kernel = local;
-      m_local_kernel = true;
-    }
-  }
-
-  static unsigned int ceil(unsigned int num, unsigned int denom) {
-    const unsigned int rounded_toward_zero = num / denom;
-    if (num > rounded_toward_zero * denom) {
-      return rounded_toward_zero + 1;
-    }
-    return rounded_toward_zero;
-  }
-
-  void executeEval(Scalar* data) const {
-    typedef typename TensorEvaluator<InputArgType, GpuDevice>::Dimensions InputDims;
-
-    const int maxSharedMem = m_device.sharedMemPerBlock();
-    const int maxThreadsPerBlock = m_device.maxHipThreadsPerBlock();
-    const int maxBlocksPerProcessor = m_device.maxHipThreadsPerMultiProcessor() / maxThreadsPerBlock;
-    const int numMultiProcessors = m_device.getNumHipMultiProcessors();
-    const int hipWarpSize = 32;
-
-    switch (NumKernelDims) {
-      case 1: {
-        const int kernel_size = m_kernelImpl.dimensions().TotalSize();
-
-        const int numX = dimensions()[m_indices[0]];
-        const int numP = dimensions().TotalSize() / numX;
-        int maxX;
-        dim3 block_size;
-
-        const int single_stride_dim =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor)
-                ? 0
-                : m_inputImpl.dimensions().rank() - 1;
-        if (m_indices[0] == single_stride_dim) {
-          // Maximum the reuse
-          const int inner_dim = ((maxSharedMem / (sizeof(Scalar)) - kernel_size + 1 + 31) / 32) * 32;
-          maxX = numext::mini<int>(inner_dim, numX);
-          const int maxP = numext::mini<int>(maxSharedMem / ((kernel_size - 1 + maxX) * sizeof(Scalar)), numP);
-          block_size.x = numext::mini(maxThreadsPerBlock, maxX);
-          block_size.y = numext::mini<int>(maxThreadsPerBlock / block_size.x, maxP);
-        }
-        else {
-          // Read as much as possible alongside the inner most dimension, that is the plane
-          const int inner_dim = maxSharedMem / ((hipWarpSize + kernel_size) * sizeof(Scalar));
-          const int maxP = numext::mini<int>(inner_dim, numP);
-          maxX = numext::mini<int>(maxSharedMem / (inner_dim * sizeof(Scalar)) - kernel_size + 1, numX);
-
-          block_size.x = numext::mini(hipWarpSize, maxX);
-          block_size.y = numext::mini<int>(maxThreadsPerBlock/block_size.x, maxP);
-        }
-
-        const int shared_mem = block_size.y * (maxX + kernel_size - 1) * sizeof(Scalar);
-        assert(shared_mem <= maxSharedMem);
-
-        const int num_x_blocks = ceil(numX, maxX);
-        const int blocksPerProcessor = numext::mini(maxBlocksPerProcessor, maxSharedMem / shared_mem);
-        const int num_y_blocks = ceil(numMultiProcessors * blocksPerProcessor, num_x_blocks);
-
-        dim3 num_blocks(num_x_blocks, numext::mini<int>(num_y_blocks, ceil(numP, block_size.y)));
-
-
-        //cout << "launching 1D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " maxX: " << maxX << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl;
-
-        const array<Index, 1> indices(m_indices[0]);
-        const array<Index, 1> kernel_dims(m_kernelImpl.dimensions()[0]);
-        internal::IndexMapper<Index, InputDims, 1, Layout> indexMapper(
-            m_inputImpl.dimensions(), kernel_dims, indices);
-        switch(kernel_size) {
-          case 4: {
-            hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel1D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 4>),
-                            dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, 4, data);
-            break;
-          }
-          case 7: {
-            hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel1D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 7>),
-                            dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, 7, data);
-            break;
-          }
-          default: {
-            hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel1D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, Dynamic>),
-                            dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, kernel_size, data);
-          }
-        }
-        break;
-      }
-
-      case 2: {
-        const int idxX =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 0 : 1;
-        const int idxY =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 1 : 0;
-        const int kernel_size_x = m_kernelImpl.dimensions()[idxX];
-        const int kernel_size_y = m_kernelImpl.dimensions()[idxY];
-
-        const int numX = dimensions()[m_indices[idxX]];
-        const int numY = dimensions()[m_indices[idxY]];
-        const int numP = dimensions().TotalSize() / (numX*numY);
-
-        const float scaling_factor = sqrtf(static_cast<float>(maxSharedMem) / (sizeof(Scalar) * kernel_size_y * kernel_size_x));
-
-        // Snap maxX to warp size
-        int inner_dim = ((static_cast<int>(scaling_factor * kernel_size_x) - kernel_size_x + 1 + 32) / 32) * 32;
-        const int maxX = numext::mini<int>(inner_dim, numX);
-        const int maxY = numext::mini<int>(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1)) - kernel_size_y + 1, numY);
-        const int maxP = numext::mini<int>(maxSharedMem / ((kernel_size_x - 1 + maxX) * (kernel_size_y - 1 + maxY) * sizeof(Scalar)), numP);
-
-        dim3 block_size;
-        block_size.x = numext::mini(1024, maxX);
-        block_size.y = numext::mini<int>(1024/block_size.x, maxY);
-        block_size.z = numext::mini<int>(1024/(block_size.x*block_size.y), maxP);
-
-        const int shared_mem = block_size.z * (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1) * sizeof(Scalar);
-        assert(shared_mem <= maxSharedMem);
-
-        const int num_x_blocks = ceil(numX, maxX);
-        const int num_y_blocks = ceil(numY, maxY);
-        const int blocksPerProcessor = numext::mini(maxBlocksPerProcessor, maxSharedMem / shared_mem);
-        const int num_z_blocks = ceil(numMultiProcessors * blocksPerProcessor, num_x_blocks * num_y_blocks);
-
-        dim3 num_blocks(num_x_blocks, num_y_blocks, numext::mini<int>(num_z_blocks, ceil(numP, block_size.z)));
-
-
-        //cout << "launching 2D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y  << " block_size.z: " << block_size.z << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " num_blocks.z: " << num_blocks.z << " maxX: " << maxX << " maxY: " << maxY << " maxP: " << maxP << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl;
-
-        const array<Index, 2> indices(m_indices[idxX], m_indices[idxY]);
-        const array<Index, 2> kernel_dims(m_kernelImpl.dimensions()[idxX],
-                                          m_kernelImpl.dimensions()[idxY]);
-        internal::IndexMapper<Index, InputDims, 2, Layout> indexMapper(
-            m_inputImpl.dimensions(), kernel_dims, indices);
-        switch (kernel_size_x) {
-          case 4: {
-            switch (kernel_size_y) {
-              case 7: {
-                hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel2D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 4, 7>),
-                                dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 4, 7, data);
-                break;
-              }
-              default: {
-                hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel2D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 4, Dynamic>),
-                                dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 4, kernel_size_y, data);
-                break;
-              }
-            }
-            break;
-          }
-          case 7: {
-            switch (kernel_size_y) {
-              case 4: {
-                hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel2D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 7, 4>),
-                                dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 7, 4, data);
-                break;
-              }
-              default: {
-                hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel2D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, 7, Dynamic>),
-                                dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 7, kernel_size_y, data);
-                break;
-              }
-            }
-            break;
-          }
-          default: {
-            hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel2D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims, Dynamic, Dynamic>),
-                            dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, kernel_size_x, kernel_size_y, data);
-            break;
-          }
-        }
-        break;
-      }
-
-      case 3: {
-        const int idxX =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 0 : 2;
-        const int idxY =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 1 : 1;
-        const int idxZ =
-            static_cast<int>(Layout) == static_cast<int>(ColMajor) ? 2 : 0;
-
-        const int kernel_size_x = m_kernelImpl.dimensions()[idxX];
-        const int kernel_size_y = m_kernelImpl.dimensions()[idxY];
-        const int kernel_size_z = m_kernelImpl.dimensions()[idxZ];
-
-        const int numX = dimensions()[m_indices[idxX]];
-        const int numY = dimensions()[m_indices[idxY]];
-        const int numZ = dimensions()[m_indices[idxZ]];
-        const int numP = dimensions().TotalSize() / (numX*numY*numZ);
-
-        const int maxX = numext::mini<int>(128, numext::mini<int>(maxSharedMem / (sizeof(Scalar) * kernel_size_y * kernel_size_z) - kernel_size_x + 1, numX));
-        const int maxY = numext::mini<int>(128, numext::mini<int>(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1) * kernel_size_z) - kernel_size_y + 1, numY));
-        const int maxZ = numext::mini<int>(128, numext::mini<int>(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1)) - kernel_size_z + 1, numZ));
-
-        dim3 block_size;
-        block_size.x = numext::mini(32, maxX);
-        block_size.y = numext::mini(32, maxY);
-        block_size.z = numext::mini<int>(1024/(block_size.x*block_size.y), maxZ);
-        dim3 num_blocks(ceil(numX, maxX), ceil(numY, maxY), ceil(numZ, maxZ));
-
-        const int shared_mem = (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1) * (maxZ + kernel_size_z - 1) * sizeof(Scalar);
-        assert(shared_mem <= maxSharedMem);
-
-        //cout << "launching 3D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y  << " block_size.z: " << block_size.z << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " num_blocks.z: " << num_blocks.z  << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl;
-        const array<Index, 3> indices(m_indices[idxX], m_indices[idxY],
-                                      m_indices[idxZ]);
-        const array<Index, 3> kernel_dims(m_kernelImpl.dimensions()[idxX],
-                                          m_kernelImpl.dimensions()[idxY],
-                                          m_kernelImpl.dimensions()[idxZ]);
-        internal::IndexMapper<Index, InputDims, 3, Layout> indexMapper(
-            m_inputImpl.dimensions(), kernel_dims, indices);
-
-        hipLaunchKernelGGL(HIP_KERNEL_NAME(EigenConvolutionKernel3D<TensorEvaluator<InputArgType, GpuDevice>, Index, InputDims>),
-                        dim3(num_blocks), dim3(block_size), shared_mem, m_device.stream(), m_inputImpl, indexMapper, m_kernel,
-                        numP, numX, maxX, numY, maxY, numZ, maxZ, kernel_size_x, kernel_size_y, kernel_size_z, data);
-        break;
-      }
-
-      default: {
-        EIGEN_STATIC_ASSERT((NumKernelDims >= 1 && NumKernelDims <= 3), THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE);
-      }
-    }
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const
-  {
-    eigen_assert(m_buf);
-    eigen_assert(index < m_dimensions.TotalSize());
-    return m_buf[index];
-  }
-
-  template<int LoadMode>
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(const Index index) const
-  {
-    eigen_assert(m_buf);
-    eigen_assert(index < m_dimensions.TotalSize());
-    return internal::ploadt<PacketReturnType, LoadMode>(m_buf+index);
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost
-  costPerCoeff(bool vectorized) const {
-    // TODO(rmlarsen): FIXME: For now, this is just a copy of the CPU cost
-    // model.
-    const double kernel_size = m_kernelImpl.dimensions().TotalSize();
-    // We ignore the use of fused multiply-add.
-    const double convolve_compute_cost =
-        TensorOpCost::AddCost<Scalar>() + TensorOpCost::MulCost<Scalar>();
-    const double firstIndex_compute_cost =
-        NumDims *
-        (2 * TensorOpCost::AddCost<Index>() + 2 * TensorOpCost::MulCost<Index>() +
-         TensorOpCost::DivCost<Index>());
-    return TensorOpCost(0, 0, firstIndex_compute_cost, vectorized, PacketSize) +
-           kernel_size * (m_inputImpl.costPerCoeff(vectorized) +
-                          m_kernelImpl.costPerCoeff(vectorized) +
-                          TensorOpCost(0, 0, convolve_compute_cost, vectorized,
-                                       PacketSize));
-  }
-
- private:
-  // No assignment (copies are needed by the kernels)
-  TensorEvaluator& operator = (const TensorEvaluator&);
-
-  TensorEvaluator<InputArgType, GpuDevice> m_inputImpl;
-  TensorEvaluator<KernelArgType, GpuDevice> m_kernelImpl;
-  KernelArgType m_kernelArg;
-  Indices m_indices;
-  Dimensions m_dimensions;
-  Scalar* m_buf;
-  const Scalar* m_kernel;
-  bool m_local_kernel;
-
-  const GpuDevice& m_device;
-};
-#endif
-
-
-} // end namespace Eigen
-
-#endif // EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceHip.h b/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceHip.h
deleted file mode 100644
index c0e1109..0000000
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceHip.h
+++ /dev/null
@@ -1,352 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#if defined(EIGEN_USE_GPU) && !defined(EIGEN_CXX11_TENSOR_TENSOR_DEVICE_HIP_H)
-#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_HIP_H
-
-#if defined(EIGEN_HIPCC)
-#include "hip/hip_runtime.h"
-#include "hip/hip_runtime_api.h"
-#endif
-#include <unistd.h> //for sleep function
-
-namespace Eigen {
-
-static const int kHipScratchSize = 1024;
-
-// This defines an interface that GPUDevice can take to use
-// HIP streams underneath.
-class StreamInterface {
- public:
-  virtual ~StreamInterface() {}
-
-  virtual const hipStream_t& stream() const = 0;
-  virtual const hipDeviceProp_t& deviceProperties() const = 0;
-
-  // Allocate memory on the actual device where the computation will run
-  virtual void* allocate(size_t num_bytes) const = 0;
-  virtual void deallocate(void* buffer) const = 0;
-
-  // Return a scratchpad buffer of size 1k
-  virtual void* scratchpad() const = 0;
-
-  // Return a semaphore. The semaphore is initially initialized to 0, and
-  // each kernel using it is responsible for resetting to 0 upon completion
-  // to maintain the invariant that the semaphore is always equal to 0 upon
-  // each kernel start.
-  virtual unsigned int* semaphore() const = 0;
-};
-
-static hipDeviceProp_t* m_deviceProperties;
-static bool m_devicePropInitialized = false;
-
-static void initializeDeviceProp() {
-  if (!m_devicePropInitialized) {
-    // Attempts to ensure proper behavior in the case of multiple threads
-    // calling this function simultaneously. This would be trivial to
-    // implement if we could use std::mutex, but unfortunately mutex don't
-    // compile with nvcc, so we resort to atomics and thread fences instead.
-    // Note that if the caller uses a compiler that doesn't support c++11 we
-    // can't ensure that the initialization is thread safe.
-#if 0 && __cplusplus >= 201103L
-    static std::atomic<bool> first(true);
-    if (first.exchange(false)) {
-#else
-    static bool first = true;
-    if (first) {
-      first = false;
-#endif
-      // We're the first thread to reach this point.
-      int num_devices;
-      hipError_t status = hipGetDeviceCount(&num_devices);
-      if (status != hipSuccess) {
-        std::cerr << "Failed to get the number of HIP devices: "
-                  << hipGetErrorString(status)
-                  << std::endl;
-        assert(status == hipSuccess);
-      }
-      m_deviceProperties = new hipDeviceProp_t[num_devices];
-      for (int i = 0; i < num_devices; ++i) {
-        status = hipGetDeviceProperties(&m_deviceProperties[i], i);
-        if (status != hipSuccess) {
-          std::cerr << "Failed to initialize HIP device #"
-                    << i
-                    << ": "
-                    << hipGetErrorString(status)
-                    << std::endl;
-          assert(status == hipSuccess);
-        }
-      }
-
-#if 0 && __cplusplus >= 201103L
-      std::atomic_thread_fence(std::memory_order_release);
-#endif
-      m_devicePropInitialized = true;
-    } else {
-      // Wait for the other thread to inititialize the properties.
-      while (!m_devicePropInitialized) {
-#if 0 && __cplusplus >= 201103L
-        std::atomic_thread_fence(std::memory_order_acquire);
-#endif
-        sleep(1);
-      }
-    }
-  }
-}
-
-static const hipStream_t default_stream = 0x00;//TODO: Use hipStreamDefault instead of 0x00;
-
-class HipStreamDevice : public StreamInterface {
- public:
-  // Use the default stream on the current device
-  HipStreamDevice() : stream_(&default_stream), scratch_(NULL), semaphore_(NULL) {
-    hipGetDevice(&device_);
-    initializeDeviceProp();
-  }
-  // Use the default stream on the specified device
-  HipStreamDevice(int device) : stream_(&default_stream), device_(device), scratch_(NULL), semaphore_(NULL) {
-    initializeDeviceProp();
-  }
-  // Use the specified stream. Note that it's the
-  // caller responsibility to ensure that the stream can run on
-  // the specified device. If no device is specified the code
-  // assumes that the stream is associated to the current gpu device.
-  HipStreamDevice(const hipStream_t* stream, int device = -1)
-      : stream_(stream), device_(device), scratch_(NULL), semaphore_(NULL) {
-    if (device < 0) {
-      hipGetDevice(&device_);
-    } else {
-      int num_devices;
-      hipError_t err = hipGetDeviceCount(&num_devices);
-      EIGEN_UNUSED_VARIABLE(err)
-      assert(err == hipSuccess);
-      assert(device < num_devices);
-      device_ = device;
-    }
-    initializeDeviceProp();
-  }
-
-  virtual ~HipStreamDevice() {
-    if (scratch_) {
-      deallocate(scratch_);
-    }
-  }
-
-  const hipStream_t& stream() const { return *stream_; }
-  const hipDeviceProp_t& deviceProperties() const {
-    return m_deviceProperties[device_];
-  }
-  virtual void* allocate(size_t num_bytes) const {
-    hipError_t err = hipSetDevice(device_);
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-    void* result;
-    err = hipMalloc(&result, num_bytes);
-    assert(err == hipSuccess);
-    assert(result != NULL);
-    return result;
-  }
-  virtual void deallocate(void* buffer) const {
-    hipError_t err = hipSetDevice(device_);
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-    assert(buffer != NULL);
-    err = hipFree(buffer);
-    assert(err == hipSuccess);
-  }
-
-  virtual void* scratchpad() const {
-    if (scratch_ == NULL) {
-      scratch_ = allocate(kHipScratchSize + sizeof(unsigned int));
-    }
-    return scratch_;
-  }
-
-  virtual unsigned int* semaphore() const {
-    if (semaphore_ == NULL) {
-      char* scratch = static_cast<char*>(scratchpad()) + kHipScratchSize;
-      semaphore_ = reinterpret_cast<unsigned int*>(scratch);
-      //hipError_t err = hipMemsetAsync(semaphore_, 0, sizeof(unsigned int), *stream_);
-      hipError_t err = hipMemset(semaphore_, 0, sizeof(unsigned int));
-      EIGEN_UNUSED_VARIABLE(err)
-      assert(err == hipSuccess);
-    }
-    return semaphore_;
-  }
-
- private:
-  const hipStream_t* stream_;
-  int device_;
-  mutable void* scratch_;
-  mutable unsigned int* semaphore_;
-};
-
-struct GpuDevice {
-  // The StreamInterface is not owned: the caller is
-  // responsible for its initialization and eventual destruction.
-  explicit GpuDevice(const StreamInterface* stream) : stream_(stream), max_blocks_(INT_MAX) {
-    eigen_assert(stream);
-  }
-  explicit GpuDevice(const StreamInterface* stream, int num_blocks) : stream_(stream), max_blocks_(num_blocks) {
-    eigen_assert(stream);
-  }
-  // TODO(bsteiner): This is an internal API, we should not expose it.
-  EIGEN_STRONG_INLINE const hipStream_t& stream() const {
-    return stream_->stream();
-  }
-
-  EIGEN_STRONG_INLINE void* allocate(size_t num_bytes) const {
-    return stream_->allocate(num_bytes);
-  }
-
-  EIGEN_STRONG_INLINE void deallocate(void* buffer) const {
-    stream_->deallocate(buffer);
-  }
-
-  EIGEN_STRONG_INLINE void* scratchpad() const {
-    return stream_->scratchpad();
-  }
-
-  EIGEN_STRONG_INLINE unsigned int* semaphore() const {
-    return stream_->semaphore();
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const {
-#if !defined(EIGEN_HIP_DEVICE_COMPILE)
-    hipError_t err = hipMemcpyAsync(dst, src, n, hipMemcpyDeviceToDevice,
-                                      stream_->stream());
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-#else
-  eigen_assert(false && "The default device should be used instead to generate kernel code");
-#endif
-  }
-
-  EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const {
-    hipError_t err =
-        hipMemcpyAsync(dst, src, n, hipMemcpyHostToDevice, stream_->stream());
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-  }
-
-   EIGEN_STRONG_INLINE void memcpyDeviceToHost(void* dst, const void* src, size_t n) const {
-    hipError_t err =
-        hipMemcpyAsync(dst, src, n, hipMemcpyDeviceToHost, stream_->stream());
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-  }
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memset(void* buffer, int c, size_t n) const {
-#if !defined(EIGEN_HIP_DEVICE_COMPILE)
-    //TODO:hipError_t err = hipMemsetAsync(buffer, c, n, stream_->stream());
-    hipError_t err = hipMemset(buffer, c, n);
-    EIGEN_UNUSED_VARIABLE(err)
-    assert(err == hipSuccess);
-#else
-  eigen_assert(false && "The default device should be used instead to generate kernel code");
-#endif
-  }
-
-  EIGEN_STRONG_INLINE size_t numThreads() const {
-    // FIXME
-    return 32;
-  }
-
-  EIGEN_STRONG_INLINE size_t firstLevelCacheSize() const {
-    // FIXME
-    return 48*1024;
-  }
-
-  EIGEN_STRONG_INLINE size_t lastLevelCacheSize() const {
-    // We won't try to take advantage of the l2 cache for the time being, and
-    // there is no l3 cache on hip devices.
-    return firstLevelCacheSize();
-  }
-
-// FIXME - this will move into HIP
-#if defined(EIGEN_HIP_DEVICE_COMPILE)
-#undef assert
-#define assert(COND)
-#endif
-
-  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void synchronize() const {
-#if defined(EIGEN_HIPCC) && \
-    !defined(EIGEN_HIP_DEVICE_COMPILE)
-    hipError_t err = hipStreamSynchronize(stream_->stream());
-    if (err != hipSuccess) {
-      std::cerr << "Error detected in HIP stream: "
-                << hipGetErrorString(err)
-                << std::endl;
-      assert(err == hipSuccess);
-    }
-#else
-    assert(false && "The default device should be used instead to generate kernel code");
-#endif
-  }
-
-  EIGEN_STRONG_INLINE int getNumHipMultiProcessors() const {
-    return stream_->deviceProperties().multiProcessorCount;
-  }
-  EIGEN_STRONG_INLINE int maxHipThreadsPerBlock() const {
-    return stream_->deviceProperties().maxThreadsPerBlock;
-  }
-  EIGEN_STRONG_INLINE int maxHipThreadsPerMultiProcessor() const {
-    return stream_->deviceProperties().maxThreadsPerMultiProcessor;
-  }
-  EIGEN_STRONG_INLINE int sharedMemPerBlock() const {
-    return stream_->deviceProperties().sharedMemPerBlock;
-  }
-   EIGEN_STRONG_INLINE int majorDeviceVersion() const {
-    return stream_->deviceProperties().major;
-  }
-  EIGEN_STRONG_INLINE int minorDeviceVersion() const {
-    return stream_->deviceProperties().minor;
-  }
-
-  EIGEN_STRONG_INLINE int maxBlocks() const {
-    return max_blocks_;
-  }
-
-  // This function checks if the HIP runtime recorded an error for the
-  // underlying stream device.
-  inline bool ok() const {
-#if defined(EIGEN_HIPCC)
-    hipError_t error = hipStreamQuery(stream_->stream());
-    return (error == hipSuccess) || (error == hipErrorNotReady);
-#else
-    return false;
-#endif
-  }
-
- private:
-  const StreamInterface* stream_;
-  int max_blocks_;
-};
-
-#define LAUNCH_HIP_KERNEL(kernel, gridsize, blocksize, sharedmem, device, ...)             \
-  hipLaunchKernelGGL(HIP_KERNEL_NAME(kernel), dim3(gridsize), dim3(blocksize), (sharedmem), (device).stream(), (__VA_ARGS__)); \
-  assert(hipGetLastError() == hipSuccess);
-
-
-// FIXME: Should be device and kernel specific.
-#if defined(EIGEN_HIPCC)
-static EIGEN_DEVICE_FUNC inline void setHipSharedMemConfig(hipSharedMemConfig config) {
-#if !defined(EIGEN_HIP_DEVICE_COMPILE)
-  hipError_t status = hipDeviceSetSharedMemConfig(config);
-  EIGEN_UNUSED_VARIABLE(status)
-  assert(status == hipSuccess);
-#else
-  EIGEN_UNUSED_VARIABLE(config)
-#endif
-}
-#endif
-
-}  // end namespace Eigen
-
-#endif  // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_HIP_H
diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorReductionHip.h b/unsupported/Eigen/CXX11/src/Tensor/TensorReductionHip.h
deleted file mode 100644
index 5304a22..0000000
--- a/unsupported/Eigen/CXX11/src/Tensor/TensorReductionHip.h
+++ /dev/null
@@ -1,815 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#ifndef EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_HIP_H
-#define EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_HIP_H
-
-#if defined(EIGEN_HIP_DEVICE_COMPILE)
-#include "Eigen/src/Core/arch/HIP/hcc/math_constants.h"
-#endif
-
-#if defined(EIGEN_HIPCC)
-#define HIP_WARP_SIZE 64
-#endif
-
-namespace Eigen {
-namespace internal {
-
-
-#if defined(EIGEN_USE_GPU) && defined(EIGEN_HIPCC)
-// Full reducers for GPU, don't vectorize for now
-
-// Reducer function that enables multiple hip thread to safely accumulate at the same
-// output address. It basically reads the current value of the output variable, and
-// attempts to update it with the new value. If in the meantime another hip thread
-// updated the content of the output address it will try again.
-template <typename T, typename R>
-__device__ EIGEN_ALWAYS_INLINE void atomicReduce(T* output, T accum, R& reducer) {
-#if defined(EIGEN_HIP_DEVICE_COMPILE) && defined(__HIP_ARCH_HAS_WARP_SHUFFLE__)
-  if (sizeof(T) == 4)
-  {
-    unsigned int oldval = *reinterpret_cast<unsigned int*>(output);
-    unsigned int newval = oldval;
-    reducer.reduce(accum, reinterpret_cast<T*>(&newval));
-    if (newval == oldval) {
-      return;
-    }
-    unsigned int readback;
-    while ((readback = atomicCAS((unsigned int*)output, oldval, newval)) != oldval) {
-      oldval = readback;
-      newval = oldval;
-      reducer.reduce(accum, reinterpret_cast<T*>(&newval));
-      if (newval == oldval) {
-        return;
-      }
-    }
-  }
-  else if (sizeof(T) == 8) {
-    unsigned long long oldval = *reinterpret_cast<unsigned long long*>(output);
-    unsigned long long newval = oldval;
-    reducer.reduce(accum, reinterpret_cast<T*>(&newval));
-    if (newval == oldval) {
-      return;
-    }
-    unsigned long long readback;
-    while ((readback = atomicCAS((unsigned long long*)output, oldval, newval)) != oldval) {
-      oldval = readback;
-      newval = oldval;
-      reducer.reduce(accum, reinterpret_cast<T*>(&newval));
-      if (newval == oldval) {
-        return;
-      }
-    }
-  }
-  else {
-    assert(0 && "Wordsize not supported");
-  }
-#else
-  assert(0 && "Shouldn't be called on unsupported device");
-#endif
-}
-
-// We extend atomicExch to support extra data types
-template <typename Type>
-__device__ inline Type atomicExchCustom(Type* address, Type val) {
-  return atomicExch(address, val);
-}
-
-template <>
-__device__ inline double atomicExchCustom(double* address, double val) {
-  unsigned long long int* address_as_ull = reinterpret_cast<unsigned long long int*>(address);
-  return __longlong_as_double(atomicExch(address_as_ull, __double_as_longlong(val)));
-}
-
-#if defined(EIGEN_HAS_HIP_FP16)
-template <template <typename T> class R>
-__device__ inline void atomicReduce(half2* output, half2 accum, R<half>& reducer) {
-  unsigned int oldval = *reinterpret_cast<unsigned int*>(output);
-  unsigned int newval = oldval;
-  reducer.reducePacket(accum, reinterpret_cast<half2*>(&newval));
-  if (newval == oldval) {
-    return;
-  }
-  unsigned int readback;
-  while ((readback = atomicCAS((unsigned int*)output, oldval, newval)) != oldval) {
-    oldval = readback;
-    newval = oldval;
-    reducer.reducePacket(accum, reinterpret_cast<half2*>(&newval));
-    if (newval == oldval) {
-      return;
-    }
-  }
-}
-#endif
-
-template <>
-__device__ inline void atomicReduce(float* output, float accum, SumReducer<float>&) {
-#if defined(EIGEN_HIP_DEVICE_COMPILE) && (__HIP_DEVICE_COMPILE__ == 1) &&\
-    defined(__HIP_ARCH_HAS_WARP_SHUFFLE__)
-  atomicAdd(output, accum);
-#else
-  assert(0 && "Shouldn't be called on unsupported device");
-#endif
-}
-
-
-template <typename CoeffType, typename Index>
-__global__ void ReductionInitKernel(const CoeffType val, Index num_preserved_coeffs, CoeffType* output) {
-  const Index thread_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
-  const Index num_threads = hipBlockDim_x * hipGridDim_x;
-  for (Index i = thread_id; i < num_preserved_coeffs; i += num_threads) {
-    output[i] = val;
-  }
-}
-
-
-template <int BlockSize, int NumPerThread, typename Self,
-          typename Reducer, typename Index>
-__global__ void FullReductionKernel(const Self input, Index num_coeffs,
-                                    typename Self::CoeffReturnType* output, unsigned int* semaphore, Reducer reducer) {
-#if defined(EIGEN_HIP_DEVICE_COMPILE) && (__HIP_DEVICE_COMPILE__ == 1) &&\
-    defined(__HIP_ARCH_HAS_WARP_SHUFFLE__)
-  // Initialize the output value
-  const Index first_index = hipBlockIdx_x * BlockSize * NumPerThread + hipThreadIdx_x;
-  if (hipGridDim_x == 1) {
-    if (first_index == 0) {
-      *output = reducer.initialize();
-    }
-  }
-  else {
-    if (hipThreadIdx_x == 0) {
-      unsigned int block = atomicCAS(semaphore, 0u, 1u);
-      if (block == 0) {
-        // We're the first block to run, initialize the output value
-        atomicExchCustom(output, reducer.initialize());
-        __threadfence();
-        atomicExch(semaphore, 2u);
-      }
-      else {
-        // Wait for the first block to initialize the output value.
-        // Use atomicCAS here to ensure that the reads aren't cached
-        unsigned int val;
-        do {
-          val = atomicCAS(semaphore, 2u, 2u);
-        }
-        while (val < 2u);
-      }
-    }
-  }
-
-  __syncthreads();
-
-  eigen_assert(hipGridDim_x == 1 || *semaphore >= 2u);
-
-  typename Self::CoeffReturnType accum = reducer.initialize();
-  Index max_iter = numext::mini<Index>(num_coeffs - first_index, NumPerThread*BlockSize);
-  for (Index i = 0; i < max_iter; i+=BlockSize) {
-    const Index index = first_index + i;
-    eigen_assert(index < num_coeffs);
-    typename Self::CoeffReturnType val = input.m_impl.coeff(index);
-    reducer.reduce(val, &accum);
-  }
-
-#pragma unroll
-  for (int offset = HIP_WARP_SIZE/2; offset > 0; offset /= 2) {
-    // XXX use std::is_floating_point to determine the type of accum
-    if (std::is_floating_point<typename Self::CoeffReturnType>::value) {
-      reducer.reduce(__shfl_down(static_cast<float>(accum), offset, HIP_WARP_SIZE), &accum);
-    } else {
-      reducer.reduce(__shfl_down(static_cast<int>(accum), offset, HIP_WARP_SIZE), &accum);
-    }
-  }
-
-  if ((hipThreadIdx_x & (HIP_WARP_SIZE - 1)) == 0) {
-    atomicReduce(output, accum, reducer);
-  }
-
-  if (hipGridDim_x > 1 && hipThreadIdx_x == 0) {
-    // Let the last block reset the semaphore
-    atomicInc(semaphore, hipGridDim_x + 1);
-    __threadfence_system();
-  }
-
-#else
-  assert(0 && "Shouldn't be called on unsupported device");
-#endif
-}
-
-
-#if defined(EIGEN_HAS_HIP_FP16)
-template <typename Self,
-          typename Reducer, typename Index>
-__global__ void ReductionInitFullReduxKernelHalfFloat(Reducer reducer, const Self input, Index num_coeffs, half2* scratch) {
-  eigen_assert(hipBlockDim_x == 1);
-  eigen_assert(hipGridDim_x == 1);
-  if (num_coeffs % 2 != 0) {
-    half last = input.m_impl.coeff(num_coeffs-1);
-    *scratch = __halves2half2(last, reducer.initialize());
-  } else {
-    *scratch = reducer.template initializePacket<half2>();
-  }
-}
-
-template <typename Self,
-          typename Reducer, typename Index>
-__global__ void ReductionInitKernelHalfFloat(Reducer reducer, const Self input, Index num_coeffs, half* output) {
-  const Index thread_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
-  const Index num_threads = hipBlockDim_x * hipGridDim_x;
-  const Index num_packets = num_coeffs / 2;
-  for (Index i = thread_id; i < num_packets; i += num_threads) {
-    ((half2*)output)[i] = reducer.template initializePacket<half2>();
-  }
-
-  if (thread_id == 0 && num_coeffs % 2 != 0) {
-    output[num_coeffs-1] = reducer.initialize();
-  }
-}
-
-template <int BlockSize, int NumPerThread, typename Self,
-          typename Reducer, typename Index>
-__global__ void FullReductionKernelHalfFloat(Reducer reducer, const Self input, Index num_coeffs,
-                                    half* output, half2* scratch) {
-  eigen_assert(NumPerThread % 2 == 0);
-
-  const Index first_index = hipBlockIdx_x * BlockSize * NumPerThread + 2*hipThreadIdx_x;
-
-  // Initialize the output value if it wasn't initialized by the ReductionInitKernel
-  if (hipGridDim_x == 1 && first_index == 0) {
-    if (num_coeffs % 2 != 0) {
-      half last = input.m_impl.coeff(num_coeffs-1);
-      *scratch = __halves2half2(last, reducer.initialize());
-    } else {
-      *scratch = reducer.template initializePacket<half2>();
-    }
-    __syncthreads();
-  }
-
-  half2 accum = reducer.template initializePacket<half2>();
-  const Index max_iter = numext::mini<Index>((num_coeffs - first_index) / 2, NumPerThread*BlockSize / 2);
-  for (Index i = 0; i < max_iter; i += BlockSize) {
-    const Index index = first_index + 2*i;
-    eigen_assert(index + 1 < num_coeffs);
-    half2 val = input.m_impl.template packet<Unaligned>(index);
-    reducer.reducePacket(val, &accum);
-  }
-
-#pragma unroll
-  for (int offset = HIP_WARP_SIZE/2; offset > 0; offset /= 2) {
-    // FIXME : remove this workaround once we have native half/half2 support for __shfl_down
-    union { int i; half2 h; } wka_in, wka_out;
-    wka_in.h = accum;
-    wka_out.i = __shfl_down(wka_in.i, offset, HIP_WARP_SIZE);
-    reducer.reducePacket(wka_out.h, &accum);
-  }
-
-  if ((hipThreadIdx_x & (HIP_WARP_SIZE - 1)) == 0) {
-    atomicReduce(scratch, accum, reducer);
-  }
-
-  __syncthreads();
-
-  if (hipGridDim_x == 1 && first_index == 0) {
-    half tmp = __low2half(*scratch);
-    reducer.reduce(__high2half(*scratch), &tmp);
-    *output = tmp;
-  }
-}
-
-template <typename Op>
-__global__ void ReductionCleanupKernelHalfFloat(Op& reducer, half* output, half2* scratch) {
-  eigen_assert(hipThreadIdx_x == 1);
-  half tmp = __low2half(*scratch);
-  reducer.reduce(__high2half(*scratch), &tmp);
-  *output = tmp;
-}
-
-#endif
-
-template <typename Self, typename Op, typename OutputType, bool PacketAccess, typename Enabled = void>
-struct FullReductionLauncher {
-  static void run(const Self&, Op&, const GpuDevice&, OutputType*, typename Self::Index) {
-    assert(false && "Should only be called on doubles, floats and half floats");
-  }
-};
-
-namespace {
-  std::mutex __eigen_reduction_hip_mutex;
-}
-
-// Specialization for float and double
-template <typename Self, typename Op, typename OutputType, bool PacketAccess>
-struct FullReductionLauncher<
-    Self, Op, OutputType, PacketAccess,
-    typename internal::enable_if<
-      internal::is_same<float, OutputType>::value ||
-      internal::is_same<double, OutputType>::value,
-    void>::type> {
-  static void run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs) {
-    // guard FullReductionLauncher with a mutex so only 1 FullReductionKernel
-    // is dispatched at a time
-    std::lock_guard<std::mutex> lock(__eigen_reduction_hip_mutex);
-
-    typedef typename Self::Index Index;
-    typedef typename Self::CoeffReturnType Scalar;
-    const int block_size = 256;
-    const int num_per_thread = 128;
-    const int num_blocks = divup<int>(num_coeffs, block_size * num_per_thread);
-
-    unsigned int* semaphore = NULL;
-    if (num_blocks > 1) {
-      semaphore = device.semaphore();
-
-      unsigned int semaphore_host = 0xFF;
-      hipMemcpy(&semaphore_host, semaphore, sizeof(unsigned int), hipMemcpyDeviceToHost);
-      if (semaphore_host != 0) {
-        std::cerr << "[WARN][EIGEN][FullReductionLauncher] incorrect semaphore value: "
-                  << semaphore_host << "\n";
-        // wait for all commands on the device to complete so semaphore value
-        // is reset to 0
-        hipDeviceSynchronize();
-
-        // read again
-        hipMemcpy(&semaphore_host, semaphore, sizeof(unsigned int), hipMemcpyDeviceToHost);
-        if (semaphore_host != 0) {
-          std::cerr << "[ERROR][EIGEN][FullReductionLauncher] CRITICAL incorrect semaphore value: "
-                    << semaphore_host << ", apply manual override to 0\n";
-
-          // force set semaphore value to be 0
-          semaphore_host = 0;
-          hipMemcpy(semaphore, &semaphore_host, sizeof(unsigned int), hipMemcpyHostToDevice);
-        }
-      }
-    }
-
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(FullReductionKernel<block_size, num_per_thread, Self, Op, Index>),
-                       dim3(num_blocks), dim3(block_size), 0, device.stream(), self, num_coeffs, output, semaphore, reducer);
-  }
-};
-
-#if defined(EIGEN_HAS_HIP_FP16)
-template <typename Self, typename Op>
-struct FullReductionLauncher<Self, Op, Eigen::half, false> {
-  static void run(const Self&, Op&, const GpuDevice&, half*, typename Self::Index) {
-    assert(false && "Should not be called since there is no packet accessor");
-  }
-};
-
-template <typename Self, typename Op>
-struct FullReductionLauncher<Self, Op, Eigen::half, true> {
-  static void run(const Self& self, Op& reducer, const GpuDevice& device, half* output, typename Self::Index num_coeffs) {
-    typedef typename Self::Index Index;
-
-    const int block_size = 256;
-    const int num_per_thread = 128;
-    const int num_blocks = divup<int>(num_coeffs, block_size * num_per_thread);
-    half2* scratch = static_cast<half2*>(device.scratchpad());
-
-    if (num_blocks > 1) {
-      // We initialize the output and the scrathpad outside the reduction kernel when we can't be sure that there
-      // won't be a race conditions between multiple thread blocks.
-      hipLaunchKernelGGL(HIP_KERNEL_NAME(ReductionInitFullReduxKernelHalfFloat<Self, Op, Index>),
-                         dim3(1), dim3(1), 0, device.stream(), reducer, self, num_coeffs, scratch);
-    }
-
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(FullReductionKernelHalfFloat<block_size, num_per_thread, Self, Op, Index>),
-                       dim3(num_blocks), dim3(block_size), 0, device.stream(), reducer, self, num_coeffs, output, scratch);
-
-    if (num_blocks > 1) {
-      hipLaunchKernelGGL(HIP_KERNEL_NAME(ReductionCleanupKernelHalfFloat<Op>),
-                         dim3(1), dim3(1), 0, device.stream(), reducer, output, scratch);
-    }
-  }
-};
-#endif
-
-
-template <typename Self, typename Op, bool Vectorizable>
-struct FullReducer<Self, Op, GpuDevice, Vectorizable> {
-  // Unfortunately nvidia doesn't support well exotic types such as complex,
-  // so reduce the scope of the optimized version of the code to the simple cases
-  // of doubles, floats and half floats
-#if defined(EIGEN_HAS_HIP_FP16)
-  static const bool HasOptimizedImplementation = !Op::IsStateful &&
-      (internal::is_same<typename Self::CoeffReturnType, float>::value ||
-       internal::is_same<typename Self::CoeffReturnType, double>::value ||
-       (internal::is_same<typename Self::CoeffReturnType, Eigen::half>::value && reducer_traits<Op, GpuDevice>::PacketAccess));
-#else
-  static const bool HasOptimizedImplementation = !Op::IsStateful &&
-                                                (internal::is_same<typename Self::CoeffReturnType, float>::value ||
-                                                 internal::is_same<typename Self::CoeffReturnType, double>::value);
-#endif
-
-  template <typename OutputType>
-  static void run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output) {
-    assert(HasOptimizedImplementation && "Should only be called on doubles, floats or half floats");
-    const Index num_coeffs = array_prod(self.m_impl.dimensions());
-    // Don't crash when we're called with an input tensor of size 0.
-    if (num_coeffs == 0) {
-      return;
-    }
-
-    FullReductionLauncher<Self, Op, OutputType, reducer_traits<Op, GpuDevice>::PacketAccess>::run(self, reducer, device, output, num_coeffs);
-  }
-};
-
-
-template <int NumPerThread, typename Self,
-          typename Reducer, typename Index>
-__global__ void InnerReductionKernel(Reducer reducer, const Self input, Index num_coeffs_to_reduce, Index num_preserved_coeffs,
-                                         typename Self::CoeffReturnType* output) {
-#if defined(EIGEN_HIP_DEVICE_COMPILE) && (__HIP_DEVICE_COMPILE__ == 1) &&\
-    defined(__HIP_ARCH_HAS_WARP_SHUFFLE__)
-  typedef typename Self::CoeffReturnType Type;
-  eigen_assert(hipBlockDim_y == 1);
-  eigen_assert(hipBlockDim_z == 1);
-  eigen_assert(hipGridDim_y == 1);
-  eigen_assert(hipGridDim_z == 1);
-
-  const int unroll_times = 16;
-  eigen_assert(NumPerThread % unroll_times == 0);
-
-  const Index input_col_blocks = divup<Index>(num_coeffs_to_reduce, hipBlockDim_x * NumPerThread);
-  const Index num_input_blocks = input_col_blocks * num_preserved_coeffs;
-
-  const Index num_threads = hipBlockDim_x * hipGridDim_x;
-  const Index thread_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
-
-  // Initialize the output values if they weren't initialized by the ReductionInitKernel
-  if (hipGridDim_x == 1) {
-    for (Index i = thread_id; i < num_preserved_coeffs; i += num_threads) {
-      output[i] = reducer.initialize();
-    }
-    __syncthreads();
-  }
-
-  for (Index i = hipBlockIdx_x; i < num_input_blocks; i += hipGridDim_x) {
-    const Index row = i / input_col_blocks;
-
-    if (row < num_preserved_coeffs) {
-      const Index col_block = i % input_col_blocks;
-      const Index col_begin = col_block * hipBlockDim_x * NumPerThread + hipThreadIdx_x;
-
-      Type reduced_val = reducer.initialize();
-
-      for (Index j = 0; j < NumPerThread; j += unroll_times) {
-        const Index last_col = col_begin + hipBlockDim_x * (j + unroll_times - 1);
-        if (last_col >= num_coeffs_to_reduce) {
-          for (Index col = col_begin + hipBlockDim_x * j; col < num_coeffs_to_reduce; col += hipBlockDim_x) {
-            const Type val = input.m_impl.coeff(row * num_coeffs_to_reduce + col);
-            reducer.reduce(val, &reduced_val);
-          }
-          break;
-        } else {
-          // Faster version of the loop with no branches after unrolling.
-#pragma unroll
-          for (int k = 0; k < unroll_times; ++k) {
-            const Index col = col_begin + hipBlockDim_x * (j + k);
-            reducer.reduce(input.m_impl.coeff(row * num_coeffs_to_reduce + col), &reduced_val);
-          }
-        }
-      }
-
-#pragma unroll
-      for (int offset = HIP_WARP_SIZE/2; offset > 0; offset /= 2) {
-        // XXX use std::is_floating_point to determine the type of reduced_val
-        if (std::is_floating_point<Type>::value) {
-          reducer.reduce(__shfl_down(static_cast<float>(reduced_val), offset), &reduced_val);
-        } else {
-          reducer.reduce(__shfl_down(static_cast<int>(reduced_val), offset), &reduced_val);
-        }
-      }
-
-      if ((hipThreadIdx_x & (HIP_WARP_SIZE - 1)) == 0) {
-        atomicReduce(&(output[row]), reduced_val, reducer);
-      }
-    }
-  }
-#else
-  assert(0 && "Shouldn't be called on unsupported device");
-#endif
-}
-
-#if defined(EIGEN_HAS_HIP_FP16)
-
-template <int NumPerThread, typename Self,
-          typename Reducer, typename Index>
-__global__ void InnerReductionKernelHalfFloat(Reducer reducer, const Self input, Index num_coeffs_to_reduce, Index num_preserved_coeffs,
-                                              half* output) {
-  eigen_assert(hipBlockDim_y == 1);
-  eigen_assert(hipBlockDim_z == 1);
-  eigen_assert(hipGridDim_y == 1);
-  eigen_assert(hipGridDim_z == 1);
-
-  const int unroll_times = 16;
-  eigen_assert(NumPerThread % unroll_times == 0);
-  eigen_assert(unroll_times % 2 == 0);
-
-  const Index input_col_blocks = divup<Index>(num_coeffs_to_reduce, hipBlockDim_x * NumPerThread * 2);
-  const Index num_input_blocks = divup<Index>(input_col_blocks * num_preserved_coeffs, 2);
-
-  const Index num_threads = hipBlockDim_x * hipGridDim_x;
-  const Index thread_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
-
-  // Initialize the output values if they weren't initialized by the ReductionInitKernel
-  if (hipGridDim_x == 1) {
-    Index i = 2*thread_id;
-    for (; i + 1 < num_preserved_coeffs; i += 2*num_threads) {
-      half* loc = output + i;
-      *((half2*)loc) = reducer.template initializePacket<half2>();
-    }
-    if (i < num_preserved_coeffs) {
-      output[i] = reducer.initialize();
-    }
-    __syncthreads();
-  }
-
-  for (Index i = hipBlockIdx_x; i < num_input_blocks; i += hipGridDim_x) {
-    const Index row = 2 * (i / input_col_blocks);
-
-    if (row + 1 < num_preserved_coeffs) {
-      const Index col_block = i % input_col_blocks;
-      const Index col_begin = 2 * (col_block * hipBlockDim_x * NumPerThread + hipThreadIdx_x);
-
-      half2 reduced_val1 = reducer.template initializePacket<half2>();
-      half2 reduced_val2 = reducer.template initializePacket<half2>();
-
-      for (Index j = 0; j < NumPerThread; j += unroll_times) {
-        const Index last_col = col_begin + hipBlockDim_x * (j + unroll_times - 1) * 2;
-        if (last_col >= num_coeffs_to_reduce) {
-          Index col = col_begin + hipBlockDim_x * j;
-          for (; col + 1 < num_coeffs_to_reduce; col += hipBlockDim_x) {
-            const half2 val1 = input.m_impl.template packet<Unaligned>(row * num_coeffs_to_reduce + col);
-            reducer.reducePacket(val1, &reduced_val1);
-            const half2 val2 = input.m_impl.template packet<Unaligned>((row+1) * num_coeffs_to_reduce + col);
-            reducer.reducePacket(val2, &reduced_val2);
-          }
-          if (col < num_coeffs_to_reduce) {
-            // Peel;
-            const half last1 = input.m_impl.coeff(row * num_coeffs_to_reduce + col);
-            const half2 val1 = __halves2half2(last1, reducer.initialize());
-            reducer.reducePacket(val1, &reduced_val1);
-            const half last2 = input.m_impl.coeff((row+1) * num_coeffs_to_reduce + col);
-            const half2 val2 = __halves2half2(last2, reducer.initialize());
-            reducer.reducePacket(val2, &reduced_val2);
-          }
-          break;
-        } else {
-          // Faster version of the loop with no branches after unrolling.
-#pragma unroll
-          for (int k = 0; k < unroll_times; ++k) {
-            const Index col = col_begin + hipBlockDim_x * (j + k) * 2;
-            reducer.reducePacket(input.m_impl.template packet<Unaligned>(row * num_coeffs_to_reduce + col), &reduced_val1);
-            reducer.reducePacket(input.m_impl.template packet<Unaligned>((row + 1)* num_coeffs_to_reduce + col), &reduced_val2);
-          }
-        }
-      }
-
-#pragma unroll
-      for (int offset = HIP_WARP_SIZE/2; offset > 0; offset /= 2) {
-	// FIXME : remove this workaround once we have native half/half2 support for __shfl_down
-	union { int i; half2 h; } wka_in, wka_out;
-
-	wka_in.h = reduced_val1;
-	wka_out.i = __shfl_down(wka_in.i, offset, HIP_WARP_SIZE);
-        reducer.reducePacket(wka_out.h, &reduced_val1);
-	
-	wka_in.h = reduced_val2;
-	wka_out.i = __shfl_down(wka_in.i, offset, HIP_WARP_SIZE);
-        reducer.reducePacket(wka_out.h, &reduced_val2);
-      }
-
-      half val1 =  __low2half(reduced_val1);
-      reducer.reduce(__high2half(reduced_val1), &val1);
-      half val2 =  __low2half(reduced_val2);
-      reducer.reduce(__high2half(reduced_val2), &val2);
-      half2 val = __halves2half2(val1, val2);
-
-      if ((hipThreadIdx_x & (HIP_WARP_SIZE - 1)) == 0) {
-        half* loc = output + row;
-        atomicReduce((half2*)loc, val, reducer);
-      }
-    }
-  }
-}
-
-#endif
-
-template <typename Self, typename Op, typename OutputType, bool PacketAccess, typename Enabled = void>
-struct InnerReductionLauncher {
-  static bool run(const Self&, Op&, const GpuDevice&, OutputType*, typename Self::Index, typename Self::Index) {
-    assert(false && "Should only be called to reduce doubles, floats and half floats on a gpu device");
-    return true;
-  }
-};
-
-// Specialization for float and double
-template <typename Self, typename Op, typename OutputType, bool PacketAccess>
-struct InnerReductionLauncher<
-  Self, Op, OutputType, PacketAccess,
-  typename internal::enable_if<
-    internal::is_same<float, OutputType>::value ||
-    internal::is_same<double, OutputType>::value,
-  void>::type> {
-  static bool run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
-    typedef typename Self::Index Index;
-
-    const Index num_coeffs = num_coeffs_to_reduce * num_preserved_vals;
-    const int block_size = 256;
-    const int num_per_thread = 128;
-    const int dyn_blocks = divup<int>(num_coeffs, block_size * num_per_thread);
-    const int max_blocks = device.getNumHipMultiProcessors() *
-                           device.maxHipThreadsPerMultiProcessor() / block_size;
-    const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-
-    if (num_blocks > 1) {
-      // We initialize the outputs outside the reduction kernel when we can't be sure that there
-      // won't be a race conditions between multiple thread blocks.
-      const int dyn_blocks = divup<int>(num_preserved_vals, 1024);
-      const int max_blocks = device.getNumHipMultiProcessors() *
-                           device.maxHipThreadsPerMultiProcessor() / 1024;
-      const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-      hipLaunchKernelGGL(HIP_KERNEL_NAME(ReductionInitKernel<OutputType, Index>),
-                         dim3(num_blocks), dim3(1024), 0, device.stream(),
-                         reducer.initialize(), num_preserved_vals, output);
-    }
-
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(InnerReductionKernel<num_per_thread, Self, Op, Index>),
-                       dim3(num_blocks), dim3(block_size), 0, device.stream(), reducer, self,
-                       num_coeffs_to_reduce, num_preserved_vals, output);
-
-    return false;
-  }
-};
-
-#if defined(EIGEN_HAS_HIP_FP16)
-template <typename Self, typename Op>
-struct InnerReductionLauncher<Self, Op, Eigen::half, false> {
-  static bool run(const Self&, Op&, const GpuDevice&, half*, typename Self::Index, typename Self::Index) {
-    assert(false && "Should not be called since there is no packet accessor");
-    return true;
-  }
-};
-
-template <typename Self, typename Op>
-struct InnerReductionLauncher<Self, Op, Eigen::half, true> {
-  static bool run(const Self& self, Op& reducer, const GpuDevice& device, half* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
-    typedef typename Self::Index Index;
-
-    if (num_preserved_vals % 2 != 0) {
-      // Not supported yet, revert to the slower code path
-      return true;
-    }
-
-    const Index num_coeffs = num_coeffs_to_reduce * num_preserved_vals;
-    const int block_size = /*256*/128;
-    const int num_per_thread = /*128*/64;
-    const int dyn_blocks = divup<int>(num_coeffs, block_size * num_per_thread);
-    const int max_blocks = device.getNumHipMultiProcessors() *
-                           device.maxHipThreadsPerMultiProcessor() / block_size;
-    const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-
-    if (num_blocks > 1) {
-      // We initialize the outputs outside the reduction kernel when we can't be sure that there
-      // won't be a race conditions between multiple thread blocks.
-      const int dyn_blocks = divup<int>(num_preserved_vals, 1024);
-      const int max_blocks = device.getNumHipMultiProcessors() *
-                           device.maxHipThreadsPerMultiProcessor() / 1024;
-      const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-      hipLaunchKernelGGL(HIP_KERNEL_NAME(ReductionInitKernelHalfFloat<Self, Op, Index>),
-                         dim3(1), dim3(1), 0, device.stream(), reducer, self, num_preserved_vals, output);
-    }
-
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(InnerReductionKernelHalfFloat<num_per_thread, Self, Op, Index>),
-                       dim3(num_blocks), dim3(block_size), 0, device.stream(), reducer, self, num_coeffs_to_reduce, num_preserved_vals, output);
-
-    return false;
-  }
-};
-#endif
-
-
-template <typename Self, typename Op>
-struct InnerReducer<Self, Op, GpuDevice> {
-  // Unfortunately nvidia doesn't support well exotic types such as complex,
-  // so reduce the scope of the optimized version of the code to the simple case
-  // of floats and half floats.
-#if defined(EIGEN_HAS_HIP_FP16)
-  static const bool HasOptimizedImplementation = !Op::IsStateful &&
-      (internal::is_same<typename Self::CoeffReturnType, float>::value ||
-       internal::is_same<typename Self::CoeffReturnType, double>::value ||
-       (internal::is_same<typename Self::CoeffReturnType, Eigen::half>::value && reducer_traits<Op, GpuDevice>::PacketAccess));
-#else
-  static const bool HasOptimizedImplementation = !Op::IsStateful &&
-                                                 (internal::is_same<typename Self::CoeffReturnType, float>::value ||
-                                                  internal::is_same<typename Self::CoeffReturnType, double>::value);
-#endif
-
-  template <typename OutputType>
-  static bool run(const Self& self, Op& reducer, const GpuDevice& device, OutputType* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
-    assert(HasOptimizedImplementation && "Should only be called on doubles, floats or half floats");
-    const Index num_coeffs = array_prod(self.m_impl.dimensions());
-    // Don't crash when we're called with an input tensor of size 0.
-    if (num_coeffs == 0) {
-      return true;
-    }
-    // It's faster to use the usual code.
-    if (num_coeffs_to_reduce <= 128) {
-      return true;
-    }
-
-    return InnerReductionLauncher<Self, Op, OutputType, reducer_traits<Op, GpuDevice>::PacketAccess>::run(self, reducer, device, output, num_coeffs_to_reduce, num_preserved_vals);
-  }
-};
-
-template <int NumPerThread, typename Self,
-          typename Reducer, typename Index>
-__global__ void OuterReductionKernel(Reducer reducer, const Self input, Index num_coeffs_to_reduce, Index num_preserved_coeffs,
-                                     typename Self::CoeffReturnType* output) {
-  const Index num_threads = hipBlockDim_x * hipGridDim_x;
-  const Index thread_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
-  // Initialize the output values if they weren't initialized by the ReductionInitKernel
-  if (hipGridDim_x == 1) {
-    for (Index i = thread_id; i < num_preserved_coeffs; i += num_threads) {
-      output[i] = reducer.initialize();
-    }
-    __syncthreads();
-  }
-
-  // Do the reduction.
-  const Index max_iter = num_preserved_coeffs * divup<Index>(num_coeffs_to_reduce, NumPerThread);
-  for (Index i = thread_id; i < max_iter; i += num_threads) {
-    const Index input_col = i % num_preserved_coeffs;
-    const Index input_row = (i / num_preserved_coeffs) * NumPerThread;
-    typename Self::CoeffReturnType reduced_val = reducer.initialize();
-    const Index max_row = numext::mini(input_row + NumPerThread, num_coeffs_to_reduce);
-    for (Index j = input_row; j < max_row; j++) {
-      typename Self::CoeffReturnType val = input.m_impl.coeff(j * num_preserved_coeffs + input_col);
-      reducer.reduce(val, &reduced_val);
-    }
-    atomicReduce(&(output[input_col]), reduced_val, reducer);
-  }
-}
-
-
-template <typename Self, typename Op>
-struct OuterReducer<Self, Op, GpuDevice> {
-  // Unfortunately nvidia doesn't support well exotic types such as complex,
-  // so reduce the scope of the optimized version of the code to the simple case
-  // of floats.
-  static const bool HasOptimizedImplementation = !Op::IsStateful &&
-                                                 (internal::is_same<typename Self::CoeffReturnType, float>::value ||
-                                                  internal::is_same<typename Self::CoeffReturnType, double>::value);
-  template <typename Device, typename OutputType>
-  static bool run(const Self&, Op&, const Device&, OutputType*, typename Self::Index, typename Self::Index) {
-    assert(false && "Should only be called to reduce doubles or floats on a gpu device");
-    return true;
-  }
-
-  static bool run(const Self& self, Op& reducer, const GpuDevice& device, float* output, typename Self::Index num_coeffs_to_reduce, typename Self::Index num_preserved_vals) {
-    typedef typename Self::Index Index;
-
-    // It's faster to use the usual code.
-    if (num_coeffs_to_reduce <= 32) {
-      return true;
-    }
-
-    const Index num_coeffs = num_coeffs_to_reduce * num_preserved_vals;
-    const int block_size = 256;
-    const int num_per_thread = 16;
-    const int dyn_blocks = divup<int>(num_coeffs, block_size * num_per_thread);
-    const int max_blocks = device.getNumHipMultiProcessors() *
-                           device.maxHipThreadsPerMultiProcessor() / block_size;
-    const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-
-    if (num_blocks > 1) {
-      // We initialize the outputs in the reduction kernel itself when we don't have to worry
-      // about race conditions between multiple thread blocks.
-      const int dyn_blocks = divup<int>(num_preserved_vals, 1024);
-      const int max_blocks = device.getNumHipMultiProcessors() *
-                             device.maxHipThreadsPerMultiProcessor() / 1024;
-      const int num_blocks = numext::mini<int>(max_blocks, dyn_blocks);
-      hipLaunchKernelGGL(HIP_KERNEL_NAME(ReductionInitKernel<float, Index>),
-                         dim3(num_blocks), dim3(1024), 0, device.stream(),
-                         reducer.initialize(), num_preserved_vals, output);
-    }
-
-    hipLaunchKernelGGL(HIP_KERNEL_NAME(OuterReductionKernel<num_per_thread, Self, Op, Index>),
-                       dim3(num_blocks), dim3(block_size), 0, device.stream(), reducer, self, num_coeffs_to_reduce, num_preserved_vals, output);
-
-    return false;
-  }
-};
-
-#endif
-
-
-} // end namespace internal
-} // end namespace Eigen
-
-#endif // EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_HIP_H
diff --git a/unsupported/test/cxx11_tensor_argmax_hip.cu b/unsupported/test/cxx11_tensor_argmax_hip.cu
deleted file mode 100644
index 57d6ca0..0000000
--- a/unsupported/test/cxx11_tensor_argmax_hip.cu
+++ /dev/null
@@ -1,251 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_FUNC cxx11_tensor_hip
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-using Eigen::Tensor;
-
-template <int Layout>
-void test_hip_simple_argmax()
-{
-  Tensor<double, 3, Layout> in(Eigen::array<DenseIndex, 3>(72,53,97));
-  Tensor<DenseIndex, 1, Layout> out_max(Eigen::array<DenseIndex, 1>(1));
-  Tensor<DenseIndex, 1, Layout> out_min(Eigen::array<DenseIndex, 1>(1));
-  in.setRandom();
-  in *= in.constant(100.0);
-  in(0, 0, 0) = -1000.0;
-  in(71, 52, 96) = 1000.0;
-
-  std::size_t in_bytes = in.size() * sizeof(double);
-  std::size_t out_bytes = out_max.size() * sizeof(DenseIndex);
-
-  double* d_in;
-  DenseIndex* d_out_max;
-  DenseIndex* d_out_min;
-  hipMalloc((void**)(&d_in), in_bytes);
-  hipMalloc((void**)(&d_out_max), out_bytes);
-  hipMalloc((void**)(&d_out_min), out_bytes);
-
-  hipMemcpy(d_in, in.data(), in_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<double, 3, Layout>, Aligned > gpu_in(d_in, Eigen::array<DenseIndex, 3>(72,53,97));
-  Eigen::TensorMap<Eigen::Tensor<DenseIndex, 1, Layout>, Aligned > gpu_out_max(d_out_max, Eigen::array<DenseIndex, 1>(1));
-  Eigen::TensorMap<Eigen::Tensor<DenseIndex, 1, Layout>, Aligned > gpu_out_min(d_out_min, Eigen::array<DenseIndex, 1>(1));
-
-  gpu_out_max.device(gpu_device) = gpu_in.argmax();
-  gpu_out_min.device(gpu_device) = gpu_in.argmin();
-
-  assert(hipMemcpyAsync(out_max.data(), d_out_max, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipMemcpyAsync(out_min.data(), d_out_min, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  VERIFY_IS_EQUAL(out_max(Eigen::array<DenseIndex, 1>(0)), 72*53*97 - 1);
-  VERIFY_IS_EQUAL(out_min(Eigen::array<DenseIndex, 1>(0)), 0);
-
-  hipFree(d_in);
-  hipFree(d_out_max);
-  hipFree(d_out_min);
-}
-
-template <int DataLayout>
-void test_hip_argmax_dim()
-{
-  Tensor<float, 4, DataLayout> tensor(2,3,5,7);
-  std::vector<int> dims;
-  dims.push_back(2); dims.push_back(3); dims.push_back(5); dims.push_back(7);
-
-  for (int dim = 0; dim < 4; ++dim) {
-    tensor.setRandom();
-    tensor = (tensor + tensor.constant(0.5)).log();
-
-    array<DenseIndex, 3> out_shape;
-    for (int d = 0; d < 3; ++d) out_shape[d] = (d < dim) ? dims[d] : dims[d+1];
-
-    Tensor<DenseIndex, 3, DataLayout> tensor_arg(out_shape);
-
-    array<DenseIndex, 4> ix;
-    for (int i = 0; i < 2; ++i) {
-      for (int j = 0; j < 3; ++j) {
-        for (int k = 0; k < 5; ++k) {
-          for (int l = 0; l < 7; ++l) {
-            ix[0] = i; ix[1] = j; ix[2] = k; ix[3] = l;
-            if (ix[dim] != 0) continue;
-            // suppose dim == 1, then for all i, k, l, set tensor(i, 0, k, l) = 10.0
-            tensor(ix) = 10.0;
-          }
-        }
-      }
-    }
-
-    std::size_t in_bytes = tensor.size() * sizeof(float);
-    std::size_t out_bytes = tensor_arg.size() * sizeof(DenseIndex);
-
-    float* d_in;
-    DenseIndex* d_out;
-    hipMalloc((void**)(&d_in), in_bytes);
-    hipMalloc((void**)(&d_out), out_bytes);
-
-    hipMemcpy(d_in, tensor.data(), in_bytes, hipMemcpyHostToDevice);
-
-    Eigen::HipStreamDevice stream;
-    Eigen::GpuDevice gpu_device(&stream);
-
-    Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout>, Aligned > gpu_in(d_in, Eigen::array<DenseIndex, 4>(2, 3, 5, 7));
-    Eigen::TensorMap<Eigen::Tensor<DenseIndex, 3, DataLayout>, Aligned > gpu_out(d_out, out_shape);
-
-    gpu_out.device(gpu_device) = gpu_in.argmax(dim);
-
-    assert(hipMemcpyAsync(tensor_arg.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-    assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-    VERIFY_IS_EQUAL(tensor_arg.size(),
-                    size_t(2*3*5*7 / tensor.dimension(dim)));
-
-    for (DenseIndex n = 0; n < tensor_arg.size(); ++n) {
-      // Expect max to be in the first index of the reduced dimension
-      VERIFY_IS_EQUAL(tensor_arg.data()[n], 0);
-    }
-
-    for (int i = 0; i < 2; ++i) {
-      for (int j = 0; j < 3; ++j) {
-        for (int k = 0; k < 5; ++k) {
-          for (int l = 0; l < 7; ++l) {
-            ix[0] = i; ix[1] = j; ix[2] = k; ix[3] = l;
-            if (ix[dim] != tensor.dimension(dim) - 1) continue;
-            // suppose dim == 1, then for all i, k, l, set tensor(i, 2, k, l) = 20.0
-            tensor(ix) = 20.0;
-          }
-        }
-      }
-    }
-
-    hipMemcpy(d_in, tensor.data(), in_bytes, hipMemcpyHostToDevice);
-
-    gpu_out.device(gpu_device) = gpu_in.argmax(dim);
-
-    assert(hipMemcpyAsync(tensor_arg.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-    assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-    for (DenseIndex n = 0; n < tensor_arg.size(); ++n) {
-      // Expect max to be in the last index of the reduced dimension
-      VERIFY_IS_EQUAL(tensor_arg.data()[n], tensor.dimension(dim) - 1);
-    }
-
-    hipFree(d_in);
-    hipFree(d_out);
-  }
-}
-
-template <int DataLayout>
-void test_hip_argmin_dim()
-{
-  Tensor<float, 4, DataLayout> tensor(2,3,5,7);
-  std::vector<int> dims;
-  dims.push_back(2); dims.push_back(3); dims.push_back(5); dims.push_back(7);
-
-  for (int dim = 0; dim < 4; ++dim) {
-    tensor.setRandom();
-    tensor = (tensor + tensor.constant(0.5)).log();
-
-    array<DenseIndex, 3> out_shape;
-    for (int d = 0; d < 3; ++d) out_shape[d] = (d < dim) ? dims[d] : dims[d+1];
-
-    Tensor<DenseIndex, 3, DataLayout> tensor_arg(out_shape);
-
-    array<DenseIndex, 4> ix;
-    for (int i = 0; i < 2; ++i) {
-      for (int j = 0; j < 3; ++j) {
-        for (int k = 0; k < 5; ++k) {
-          for (int l = 0; l < 7; ++l) {
-            ix[0] = i; ix[1] = j; ix[2] = k; ix[3] = l;
-            if (ix[dim] != 0) continue;
-            // suppose dim == 1, then for all i, k, l, set tensor(i, 0, k, l) = 10.0
-            tensor(ix) = -10.0;
-          }
-        }
-      }
-    }
-
-    std::size_t in_bytes = tensor.size() * sizeof(float);
-    std::size_t out_bytes = tensor_arg.size() * sizeof(DenseIndex);
-
-    float* d_in;
-    DenseIndex* d_out;
-    hipMalloc((void**)(&d_in), in_bytes);
-    hipMalloc((void**)(&d_out), out_bytes);
-
-    hipMemcpy(d_in, tensor.data(), in_bytes, hipMemcpyHostToDevice);
-
-    Eigen::HipStreamDevice stream;
-    Eigen::GpuDevice gpu_device(&stream);
-
-    Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout>, Aligned > gpu_in(d_in, Eigen::array<DenseIndex, 4>(2, 3, 5, 7));
-    Eigen::TensorMap<Eigen::Tensor<DenseIndex, 3, DataLayout>, Aligned > gpu_out(d_out, out_shape);
-
-    gpu_out.device(gpu_device) = gpu_in.argmin(dim);
-
-    assert(hipMemcpyAsync(tensor_arg.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-    assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-    VERIFY_IS_EQUAL(tensor_arg.size(),
-                    2*3*5*7 / tensor.dimension(dim));
-
-    for (DenseIndex n = 0; n < tensor_arg.size(); ++n) {
-      // Expect min to be in the first index of the reduced dimension
-      VERIFY_IS_EQUAL(tensor_arg.data()[n], 0);
-    }
-
-    for (int i = 0; i < 2; ++i) {
-      for (int j = 0; j < 3; ++j) {
-        for (int k = 0; k < 5; ++k) {
-          for (int l = 0; l < 7; ++l) {
-            ix[0] = i; ix[1] = j; ix[2] = k; ix[3] = l;
-            if (ix[dim] != tensor.dimension(dim) - 1) continue;
-            // suppose dim == 1, then for all i, k, l, set tensor(i, 2, k, l) = 20.0
-            tensor(ix) = -20.0;
-          }
-        }
-      }
-    }
-
-    hipMemcpy(d_in, tensor.data(), in_bytes, hipMemcpyHostToDevice);
-
-    gpu_out.device(gpu_device) = gpu_in.argmin(dim);
-
-    assert(hipMemcpyAsync(tensor_arg.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-    assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-    for (DenseIndex n = 0; n < tensor_arg.size(); ++n) {
-      // Expect max to be in the last index of the reduced dimension
-      VERIFY_IS_EQUAL(tensor_arg.data()[n], tensor.dimension(dim) - 1);
-    }
-
-    hipFree(d_in);
-    hipFree(d_out);
-  }
-}
-
-void test_cxx11_tensor_hip()
-{
-  CALL_SUBTEST(test_hip_simple_argmax<RowMajor>());
-  CALL_SUBTEST(test_hip_simple_argmax<ColMajor>());
-  CALL_SUBTEST(test_hip_argmax_dim<RowMajor>());
-  CALL_SUBTEST(test_hip_argmax_dim<ColMajor>());
-  CALL_SUBTEST(test_hip_argmin_dim<RowMajor>());
-  CALL_SUBTEST(test_hip_argmin_dim<ColMajor>());
-}
diff --git a/unsupported/test/cxx11_tensor_cast_float16_hip.cu b/unsupported/test/cxx11_tensor_cast_float16_hip.cu
deleted file mode 100644
index bf6a49d..0000000
--- a/unsupported/test/cxx11_tensor_cast_float16_hip.cu
+++ /dev/null
@@ -1,79 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_cast_float16_hip
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-using Eigen::Tensor;
-
-void test_hip_conversion() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  Tensor<float, 1> floats(num_elem);
-  floats.setRandom();
-
-  float* d_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  float* d_conv = (float*)gpu_device.allocate(num_elem * sizeof(float));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float(
-      d_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_half(
-      d_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_conv(
-      d_conv, num_elem);
-
-  gpu_device.memcpyHostToDevice(d_float, floats.data(), num_elem*sizeof(float));
-
-  gpu_half.device(gpu_device) = gpu_float.cast<Eigen::half>();
-  gpu_conv.device(gpu_device) = gpu_half.cast<float>();
-
-  Tensor<float, 1> initial(num_elem);
-  Tensor<float, 1> final(num_elem);
-  gpu_device.memcpyDeviceToHost(initial.data(), d_float, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(final.data(), d_conv, num_elem*sizeof(float));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    VERIFY_IS_APPROX(initial(i), final(i));
-  }
-
-  gpu_device.deallocate(d_float);
-  gpu_device.deallocate(d_half);
-  gpu_device.deallocate(d_conv);
-}
-
-
-void test_fallback_conversion() {
-  int num_elem = 101;
-  Tensor<float, 1> floats(num_elem);
-  floats.setRandom();
-
-  Eigen::Tensor<Eigen::half, 1> halfs = floats.cast<Eigen::half>();
-  Eigen::Tensor<float, 1> conv = halfs.cast<float>();
-
-  for (int i = 0; i < num_elem; ++i) {
-    VERIFY_IS_APPROX(floats(i), conv(i));
-  }
-}
-
-
-void test_cxx11_tensor_cast_float16_hip()
-{
-  CALL_SUBTEST(test_hip_conversion());
-  CALL_SUBTEST(test_fallback_conversion());
-}
diff --git a/unsupported/test/cxx11_tensor_contract_hip.cu b/unsupported/test/cxx11_tensor_contract_hip.cu
deleted file mode 100644
index 652af0a..0000000
--- a/unsupported/test/cxx11_tensor_contract_hip.cu
+++ /dev/null
@@ -1,215 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-// Copyright (C) 2014 Navdeep Jaitly <ndjaitly@google.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_hip
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-
-using Eigen::Tensor;
-typedef Tensor<float, 1>::DimensionPair DimPair;
-
-template<int DataLayout>
-void test_hip_contraction(int m_size, int k_size, int n_size)
-{
-  std::cout << "Testing for (" << m_size << "," << k_size << "," << n_size << ")" << std::endl;
-  // with these dimensions, the output has 300 * 140 elements, which is
-  // more than 30 * 1024, which is the number of threads in blocks on
-  // a 15 SM GK110 GPU
-  Tensor<float, 2, DataLayout> t_left(m_size, k_size);
-  Tensor<float, 2, DataLayout> t_right(k_size, n_size);
-  Tensor<float, 2, DataLayout> t_result(m_size, n_size);
-  Tensor<float, 2, DataLayout> t_result_gpu(m_size, n_size);
-  Eigen::array<DimPair, 1> dims(DimPair(1, 0));
-
-  t_left.setRandom();
-  t_right.setRandom();
-
-  std::size_t t_left_bytes = t_left.size()  * sizeof(float);
-  std::size_t t_right_bytes = t_right.size() * sizeof(float);
-  std::size_t t_result_bytes = t_result.size() * sizeof(float);
-
-  float* d_t_left;
-  float* d_t_right;
-  float* d_t_result;
-
-  hipMalloc((void**)(&d_t_left), t_left_bytes);
-  hipMalloc((void**)(&d_t_right), t_right_bytes);
-  hipMalloc((void**)(&d_t_result), t_result_bytes);
-
-  hipMemcpy(d_t_left, t_left.data(), t_left_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_t_right, t_right.data(), t_right_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
-      gpu_t_left(d_t_left, Eigen::array<int, 2>(m_size, k_size));
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
-      gpu_t_right(d_t_right, Eigen::array<int, 2>(k_size, n_size));
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
-      gpu_t_result(d_t_result, Eigen::array<int, 2>(m_size, n_size));
-
-
-  gpu_t_result.device(gpu_device) = gpu_t_left.contract(gpu_t_right, dims);
-  t_result = t_left.contract(t_right, dims);
-
-  hipMemcpy(t_result_gpu.data(), d_t_result, t_result_bytes, hipMemcpyDeviceToHost);
-  for (DenseIndex i = 0; i < t_result.size(); i++) {
-    if (fabs(t_result(i) - t_result_gpu(i)) < 1e-4f) {
-      continue;
-    }
-    if (Eigen::internal::isApprox(t_result(i), t_result_gpu(i), 1e-4f)) {
-      continue;
-    }
-    std::cout << "mismatch detected at index " << i << ": " << t_result(i)
-              << " vs " <<  t_result_gpu(i) << std::endl;
-    assert(false);
-  }
-
-  hipFree((void*)d_t_left);
-  hipFree((void*)d_t_right);
-  hipFree((void*)d_t_result);
-}
-
-
-template<int DataLayout>
-void test_scalar(int m_size, int k_size, int n_size)
-{
-  std::cout << "Testing for (" << m_size << "," << k_size << "," << n_size << ")" << std::endl;
-  // with these dimensions, the output has 300 * 140 elements, which is
-  // more than 30 * 1024, which is the number of threads in blocks on
-  // a 15 SM GK110 GPU
-  Tensor<float, 2, DataLayout> t_left(m_size, k_size);
-  Tensor<float, 2, DataLayout> t_right(k_size, n_size);
-  Tensor<float, 0, DataLayout> t_result;
-  Tensor<float, 0, DataLayout> t_result_gpu;
-  Eigen::array<DimPair, 2> dims(DimPair(0, 0), DimPair(1, 1));
-
-  t_left.setRandom();
-  t_right.setRandom();
-
-  std::size_t t_left_bytes = t_left.size()  * sizeof(float);
-  std::size_t t_right_bytes = t_right.size() * sizeof(float);
-  std::size_t t_result_bytes = sizeof(float);
-
-  float* d_t_left;
-  float* d_t_right;
-  float* d_t_result;
-
-  hipMalloc((void**)(&d_t_left), t_left_bytes);
-  hipMalloc((void**)(&d_t_right), t_right_bytes);
-  hipMalloc((void**)(&d_t_result), t_result_bytes);
-
-  hipMemcpy(d_t_left, t_left.data(), t_left_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_t_right, t_right.data(), t_right_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
-      gpu_t_left(d_t_left, m_size, k_size);
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
-      gpu_t_right(d_t_right, k_size, n_size);
-  Eigen::TensorMap<Eigen::Tensor<float, 0, DataLayout> >
-      gpu_t_result(d_t_result);
-
-  gpu_t_result.device(gpu_device) = gpu_t_left.contract(gpu_t_right, dims);
-  t_result = t_left.contract(t_right, dims);
-
-  hipMemcpy(t_result_gpu.data(), d_t_result, t_result_bytes, hipMemcpyDeviceToHost);
-  if (fabs(t_result() - t_result_gpu()) > 1e-4f &&
-      !Eigen::internal::isApprox(t_result(), t_result_gpu(), 1e-4f)) {
-    std::cout << "mismatch detected: " << t_result()
-              << " vs " <<  t_result_gpu() << std::endl;
-    assert(false);
-  }
-
-  hipFree((void*)d_t_left);
-  hipFree((void*)d_t_right);
-  hipFree((void*)d_t_result);
-}
-
-
-template<int DataLayout>
-void test_hip_contraction_m() {
-  for (int k = 32; k < 256; k++) {
-    test_hip_contraction<ColMajor>(k, 128, 128);
-    test_hip_contraction<RowMajor>(k, 128, 128);
-  }
-}
-
-template<int DataLayout>
-void test_hip_contraction_k() {
-  for (int k = 32; k < 256; k++) {
-    test_hip_contraction<ColMajor>(128, k, 128);
-    test_hip_contraction<RowMajor>(128, k, 128);
-  }
-}
-
-template<int DataLayout>
-void test_hip_contraction_n() {
-  for (int k = 32; k < 256; k++) {
-    test_hip_contraction<ColMajor>(128, 128, k);
-    test_hip_contraction<RowMajor>(128, 128, k);
-  }
-}
-
-
-template<int DataLayout>
-void test_hip_contraction_sizes() {
-  int m_sizes[] = { 31,  39,   63,   64,   65,
-                   127, 129,  255,  257 , 511,
-                   512, 513, 1023, 1024, 1025};
-
-  int n_sizes[] = { 31,  39,   63,   64,   65,
-                   127, 129,  255,  257,  511,
-                   512, 513, 1023, 1024, 1025};
-
-  int k_sizes[] = {  31,   39,  63,  64,   65,
-                     95,   96, 127, 129,  255,
-                    257,  511, 512, 513, 1023,
-                   1024, 1025};
-
-  for (int i = 0; i < 15; i++) {
-    for (int j = 0; j < 15; j++) {
-      for (int k = 0; k < 17; k++) {
-        test_hip_contraction<DataLayout>(m_sizes[i], n_sizes[j], k_sizes[k]);
-      }
-    }
-  }
-}
-
-void test_cxx11_tensor_hip()
-{
-  CALL_SUBTEST(test_hip_contraction<ColMajor>(128, 128, 128));
-  CALL_SUBTEST(test_hip_contraction<RowMajor>(128, 128, 128));
-
-  CALL_SUBTEST(test_scalar<ColMajor>(128, 128, 128));
-  CALL_SUBTEST(test_scalar<RowMajor>(128, 128, 128));
-
-  CALL_SUBTEST(test_hip_contraction_m<ColMajor>());
-  CALL_SUBTEST(test_hip_contraction_m<RowMajor>());
-
-  CALL_SUBTEST(test_hip_contraction_k<ColMajor>());
-  CALL_SUBTEST(test_hip_contraction_k<RowMajor>());
-
-  CALL_SUBTEST(test_hip_contraction_n<ColMajor>());
-  CALL_SUBTEST(test_hip_contraction_n<RowMajor>());
-
-  // Commenting out these tests due to long runtimes
-  // CALL_SUBTEST(test_hip_contraction_sizes<ColMajor>());
-  // CALL_SUBTEST(test_hip_contraction_sizes<RowMajor>());
-}
diff --git a/unsupported/test/cxx11_tensor_device_hip.cu b/unsupported/test/cxx11_tensor_device_hip.cu
deleted file mode 100644
index b98c481..0000000
--- a/unsupported/test/cxx11_tensor_device_hip.cu
+++ /dev/null
@@ -1,389 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_device
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-using Eigen::Tensor;
-using Eigen::RowMajor;
-
-// Context for evaluation on cpu
-struct CPUContext {
-  CPUContext(const Eigen::Tensor<float, 3>& in1, Eigen::Tensor<float, 3>& in2, Eigen::Tensor<float, 3>& out) : in1_(in1), in2_(in2), out_(out), kernel_1d_(2), kernel_2d_(2,2), kernel_3d_(2,2,2) {
-    kernel_1d_(0) = 3.14f;
-    kernel_1d_(1) = 2.7f;
-
-    kernel_2d_(0,0) = 3.14f;
-    kernel_2d_(1,0) = 2.7f;
-    kernel_2d_(0,1) = 0.2f;
-    kernel_2d_(1,1) = 7.0f;
-
-    kernel_3d_(0,0,0) = 3.14f;
-    kernel_3d_(0,1,0) = 2.7f;
-    kernel_3d_(0,0,1) = 0.2f;
-    kernel_3d_(0,1,1) = 7.0f;
-    kernel_3d_(1,0,0) = -1.0f;
-    kernel_3d_(1,1,0) = -0.3f;
-    kernel_3d_(1,0,1) = -0.7f;
-    kernel_3d_(1,1,1) = -0.5f;
-  }
-
-  const Eigen::DefaultDevice& device() const { return cpu_device_; }
-
-  const Eigen::Tensor<float, 3>& in1() const { return in1_; }
-  const Eigen::Tensor<float, 3>& in2() const { return in2_; }
-  Eigen::Tensor<float, 3>& out() { return out_; }
-  const Eigen::Tensor<float, 1>& kernel1d() const { return kernel_1d_; }
-  const Eigen::Tensor<float, 2>& kernel2d() const { return kernel_2d_; }
-  const Eigen::Tensor<float, 3>& kernel3d() const { return kernel_3d_; }
-
- private:
-  const Eigen::Tensor<float, 3>& in1_;
-  const Eigen::Tensor<float, 3>& in2_;
-  Eigen::Tensor<float, 3>& out_;
-
-  Eigen::Tensor<float, 1> kernel_1d_;
-  Eigen::Tensor<float, 2> kernel_2d_;
-  Eigen::Tensor<float, 3> kernel_3d_;
-
-  Eigen::DefaultDevice cpu_device_;
-};
-
-
-// Context for evaluation on GPU
-struct GPUContext {
-  GPUContext(const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1, Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2, Eigen::TensorMap<Eigen::Tensor<float, 3> >& out) : in1_(in1), in2_(in2), out_(out), gpu_device_(&stream_) {
-    assert(hipMalloc((void**)(&kernel_1d_), 2*sizeof(float)) == hipSuccess);
-    float kernel_1d_val[] = {3.14f, 2.7f};
-    assert(hipMemcpy(kernel_1d_, kernel_1d_val, 2*sizeof(float), hipMemcpyHostToDevice) == hipSuccess);
-
-    assert(hipMalloc((void**)(&kernel_2d_), 4*sizeof(float)) == hipSuccess);
-    float kernel_2d_val[] = {3.14f, 2.7f, 0.2f, 7.0f};
-    assert(hipMemcpy(kernel_2d_, kernel_2d_val, 4*sizeof(float), hipMemcpyHostToDevice) == hipSuccess);
-
-    assert(hipMalloc((void**)(&kernel_3d_), 8*sizeof(float)) == hipSuccess);
-    float kernel_3d_val[] = {3.14f, -1.0f, 2.7f, -0.3f, 0.2f, -0.7f, 7.0f, -0.5f};
-    assert(hipMemcpy(kernel_3d_, kernel_3d_val, 8*sizeof(float), hipMemcpyHostToDevice) == hipSuccess);
-  }
-  ~GPUContext() {
-    assert(hipFree(kernel_1d_) == hipSuccess);
-    assert(hipFree(kernel_2d_) == hipSuccess);
-    assert(hipFree(kernel_3d_) == hipSuccess);
-  }
-
-  const Eigen::GpuDevice& device() const { return gpu_device_; }
-
-  const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1() const { return in1_; }
-  const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2() const { return in2_; }
-  Eigen::TensorMap<Eigen::Tensor<float, 3> >& out() { return out_; }
-  Eigen::TensorMap<Eigen::Tensor<float, 1> > kernel1d() const { return Eigen::TensorMap<Eigen::Tensor<float, 1> >(kernel_1d_, 2); }
-  Eigen::TensorMap<Eigen::Tensor<float, 2> > kernel2d() const { return Eigen::TensorMap<Eigen::Tensor<float, 2> >(kernel_2d_, 2, 2); }
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > kernel3d() const { return Eigen::TensorMap<Eigen::Tensor<float, 3> >(kernel_3d_, 2, 2, 2); }
-
- private:
-  const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1_;
-  const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2_;
-  Eigen::TensorMap<Eigen::Tensor<float, 3> >& out_;
-
-  float* kernel_1d_;
-  float* kernel_2d_;
-  float* kernel_3d_;
-
-  Eigen::HipStreamDevice stream_;
-  Eigen::GpuDevice gpu_device_;
-};
-
-
-// The actual expression to evaluate
-template <typename Context>
-void test_contextual_eval(Context* context)
-{
-  context->out().device(context->device()) = context->in1() + context->in2() * 3.14f + context->in1().constant(2.718f);
-}
-
-template <typename Context>
-void test_forced_contextual_eval(Context* context)
-{
-  context->out().device(context->device()) = (context->in1() + context->in2()).eval() * 3.14f + context->in1().constant(2.718f);
-}
-
-template <typename Context>
-void test_compound_assignment(Context* context)
-{
-  context->out().device(context->device()) = context->in1().constant(2.718f);
-  context->out().device(context->device()) += context->in1() + context->in2() * 3.14f;
-}
-
-
-template <typename Context>
-void test_contraction(Context* context)
-{
-  Eigen::array<std::pair<int, int>, 2> dims;
-  dims[0] = std::make_pair(1, 1);
-  dims[1] = std::make_pair(2, 2);
-
-  Eigen::array<int, 2> shape(40, 50*70);
-
-  Eigen::DSizes<int, 2> indices(0,0);
-  Eigen::DSizes<int, 2> sizes(40,40);
-
-  context->out().reshape(shape).slice(indices, sizes).device(context->device()) = context->in1().contract(context->in2(), dims);
-}
-
-
-template <typename Context>
-void test_1d_convolution(Context* context)
-{
-  Eigen::DSizes<int, 3> indices(0,0,0);
-  Eigen::DSizes<int, 3> sizes(40,49,70);
-
-  Eigen::array<int, 1> dims(1);
-  context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel1d(), dims);
-}
-
-template <typename Context>
-void test_2d_convolution(Context* context)
-{
-  Eigen::DSizes<int, 3> indices(0,0,0);
-  Eigen::DSizes<int, 3> sizes(40,49,69);
-
-  Eigen::array<int, 2> dims(1,2);
-  context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel2d(), dims);
-}
-
-template <typename Context>
-void test_3d_convolution(Context* context)
-{
-  Eigen::DSizes<int, 3> indices(0,0,0);
-  Eigen::DSizes<int, 3> sizes(39,49,69);
-
-  Eigen::array<int, 3> dims(0,1,2);
-  context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel3d(), dims);
-}
-
-
-void test_cpu() {
-  Eigen::Tensor<float, 3> in1(40,50,70);
-  Eigen::Tensor<float, 3> in2(40,50,70);
-  Eigen::Tensor<float, 3> out(40,50,70);
-
-  in1 = in1.random() + in1.constant(10.0f);
-  in2 = in2.random() + in2.constant(10.0f);
-
-  CPUContext context(in1, in2, out);
-  test_contextual_eval(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_forced_contextual_eval(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) + in2(i,j,k)) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_compound_assignment(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_contraction(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 40; ++j) {
-      const float result = out(i,j,0);
-      float expected = 0;
-      for (int k = 0; k < 50; ++k) {
-        for (int l = 0; l < 70; ++l) {
-          expected += in1(i, k, l) * in2(j, k, l);
-        }
-      }
-      VERIFY_IS_APPROX(expected, result);
-    }
-  }
-
-  test_1d_convolution(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f));
-      }
-    }
-  }
-
-  test_2d_convolution(&context);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 69; ++k) {
-        const float result = out(i,j,k);
-        const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f) +
-                               (in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f);
-        if (fabs(expected) < 1e-4f && fabs(result) < 1e-4f) {
-          continue;
-        }
-        VERIFY_IS_APPROX(expected, result);
-      }
-    }
-  }
-
-  test_3d_convolution(&context);
-  for (int i = 0; i < 39; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 69; ++k) {
-        const float result = out(i,j,k);
-        const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
-                                in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f) +
-                               (in1(i+1,j,k) * -1.0f + in1(i+1,j+1,k) * -0.3f +
-                                in1(i+1,j,k+1) * -0.7f + in1(i+1,j+1,k+1) * -0.5f);
-        if (fabs(expected) < 1e-4f && fabs(result) < 1e-4f) {
-          continue;
-        }
-        VERIFY_IS_APPROX(expected, result);
-      }
-    }
-  }
-}
-
-void test_gpu() {
-  Eigen::Tensor<float, 3> in1(40,50,70);
-  Eigen::Tensor<float, 3> in2(40,50,70);
-  Eigen::Tensor<float, 3> out(40,50,70);
-  in1 = in1.random() + in1.constant(10.0f);
-  in2 = in2.random() + in2.constant(10.0f);
-
-  std::size_t in1_bytes = in1.size() * sizeof(float);
-  std::size_t in2_bytes = in2.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_in1;
-  float* d_in2;
-  float* d_out;
-  hipMalloc((void**)(&d_in1), in1_bytes);
-  hipMalloc((void**)(&d_in2), in2_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_in1, in1.data(), in1_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in2, in2.data(), in2_bytes, hipMemcpyHostToDevice);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in1(d_in1, 40,50,70);
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in2(d_in2, 40,50,70);
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_out(d_out, 40,50,70);
-
-  GPUContext context(gpu_in1, gpu_in2, gpu_out);
-  test_contextual_eval(&context);
-  assert(hipMemcpy(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_forced_contextual_eval(&context);
-  assert(hipMemcpy(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) + in2(i,j,k)) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_compound_assignment(&context);
-  assert(hipMemcpy(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 50; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
-      }
-    }
-  }
-
-  test_contraction(&context);
-  assert(hipMemcpy(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 40; ++j) {
-      const float result = out(i,j,0);
-      float expected = 0;
-      for (int k = 0; k < 50; ++k) {
-        for (int l = 0; l < 70; ++l) {
-          expected += in1(i, k, l) * in2(j, k, l);
-        }
-      }
-      VERIFY_IS_APPROX(expected, result);
-    }
-  }
-
-  test_1d_convolution(&context);
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, context.device().stream()) == hipSuccess);
-  assert(hipStreamSynchronize(context.device().stream()) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 70; ++k) {
-        VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f));
-      }
-    }
-  }
-
-  test_2d_convolution(&context);
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, context.device().stream()) == hipSuccess);
-  assert(hipStreamSynchronize(context.device().stream()) == hipSuccess);
-  for (int i = 0; i < 40; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 69; ++k) {
-        const float result = out(i,j,k);
-        const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
-                                in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f);
-        VERIFY_IS_APPROX(expected, result);
-      }
-    }
-  }
-
-  /*
-  test_3d_convolution(&context);
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, context.device().stream()) == hipSuccess);
-  assert(hipStreamSynchronize(context.device().stream()) == hipSuccess);
-  for (int i = 0; i < 39; ++i) {
-    for (int j = 0; j < 49; ++j) {
-      for (int k = 0; k < 69; ++k) {
-       const float result = out(i,j,k);
-        const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
-                                in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f +
-                                in1(i+1,j,k) * -1.0f + in1(i+1,j+1,k) * -0.3f +
-                                in1(i+1,j,k+1) * -0.7f + in1(i+1,j+1,k+1) * -0.5f);
-        VERIFY_IS_APPROX(expected, result);
-      }
-    }
-  }
-  */
-}
-
-
-void test_cxx11_tensor_device()
-{
-  CALL_SUBTEST(test_cpu());
-  CALL_SUBTEST(test_gpu());
-}
diff --git a/unsupported/test/cxx11_tensor_hip.cu b/unsupported/test/cxx11_tensor_hip.cu
deleted file mode 100644
index b288402..0000000
--- a/unsupported/test/cxx11_tensor_hip.cu
+++ /dev/null
@@ -1,1295 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_hip
-#define EIGEN_USE_GPU
-
-#ifdef __NVCC__
-#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 70500
-#include <cuda_fp16.h>
-#endif
-#endif
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-using Eigen::Tensor;
-
-void test_hip_nullary() {
-  Tensor<float, 1, 0, int> in1(2);
-  Tensor<float, 1, 0, int> in2(2);
-  in1.setRandom();
-  in2.setRandom();
-
-  std::size_t tensor_bytes = in1.size() * sizeof(float);
-
-  float* d_in1;
-  float* d_in2;
-  hipMalloc((void**)(&d_in1), tensor_bytes);
-  hipMalloc((void**)(&d_in2), tensor_bytes);
-  hipMemcpy(d_in1, in1.data(), tensor_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in2, in2.data(), tensor_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1, 0, int>, Eigen::Aligned> gpu_in1(
-      d_in1, 2);
-  Eigen::TensorMap<Eigen::Tensor<float, 1, 0, int>, Eigen::Aligned> gpu_in2(
-      d_in2, 2);
-
-  gpu_in1.device(gpu_device) = gpu_in1.constant(3.14f);
-  gpu_in2.device(gpu_device) = gpu_in2.random();
-
-  Tensor<float, 1, 0, int> new1(2);
-  Tensor<float, 1, 0, int> new2(2);
-
-  assert(hipMemcpyAsync(new1.data(), d_in1, tensor_bytes, hipMemcpyDeviceToHost,
-                         gpu_device.stream()) == hipSuccess);
-  assert(hipMemcpyAsync(new2.data(), d_in2, tensor_bytes, hipMemcpyDeviceToHost,
-                         gpu_device.stream()) == hipSuccess);
-
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 2; ++i) {
-    VERIFY_IS_APPROX(new1(i), 3.14f);
-    VERIFY_IS_NOT_EQUAL(new2(i), in2(i));
-  }
-
-  hipFree(d_in1);
-  hipFree(d_in2);
-}
-
-void test_hip_elementwise_small() {
-  Tensor<float, 1> in1(Eigen::array<Eigen::DenseIndex, 1>{2});
-  Tensor<float, 1> in2(Eigen::array<Eigen::DenseIndex, 1>{2});
-  Tensor<float, 1> out(Eigen::array<Eigen::DenseIndex, 1>{2});
-  in1.setRandom();
-  in2.setRandom();
-
-  std::size_t in1_bytes = in1.size() * sizeof(float);
-  std::size_t in2_bytes = in2.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_in1;
-  float* d_in2;
-  float* d_out;
-  hipMalloc((void**)(&d_in1), in1_bytes);
-  hipMalloc((void**)(&d_in2), in2_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_in1, in1.data(), in1_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in2, in2.data(), in2_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_in1(
-      d_in1, Eigen::array<Eigen::DenseIndex, 1>{2});
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_in2(
-      d_in2, Eigen::array<Eigen::DenseIndex, 1>{2});
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_out(
-      d_out, Eigen::array<Eigen::DenseIndex, 1>{2});
-
-  gpu_out.device(gpu_device) = gpu_in1 + gpu_in2;
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost,
-                         gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 2; ++i) {
-    VERIFY_IS_APPROX(
-        out(Eigen::array<Eigen::DenseIndex, 1>{i}),
-        in1(Eigen::array<Eigen::DenseIndex, 1>{i}) + in2(Eigen::array<Eigen::DenseIndex, 1>{i}));
-  }
-
-  hipFree(d_in1);
-  hipFree(d_in2);
-  hipFree(d_out);
-}
-
-void test_hip_elementwise()
-{
-  Tensor<float, 3> in1(Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Tensor<float, 3> in2(Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Tensor<float, 3> in3(Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Tensor<float, 3> out(Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  in1.setRandom();
-  in2.setRandom();
-  in3.setRandom();
-
-  std::size_t in1_bytes = in1.size() * sizeof(float);
-  std::size_t in2_bytes = in2.size() * sizeof(float);
-  std::size_t in3_bytes = in3.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_in1;
-  float* d_in2;
-  float* d_in3;
-  float* d_out;
-  hipMalloc((void**)(&d_in1), in1_bytes);
-  hipMalloc((void**)(&d_in2), in2_bytes);
-  hipMalloc((void**)(&d_in3), in3_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_in1, in1.data(), in1_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in2, in2.data(), in2_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in3, in3.data(), in3_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in1(d_in1, Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in2(d_in2, Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in3(d_in3, Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-  Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_out(d_out, Eigen::array<Eigen::DenseIndex, 3>{72,53,97});
-
-  gpu_out.device(gpu_device) = gpu_in1 + gpu_in2 * gpu_in3;
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 72; ++i) {
-    for (int j = 0; j < 53; ++j) {
-      for (int k = 0; k < 97; ++k) {
-        VERIFY_IS_APPROX(out(Eigen::array<Eigen::DenseIndex, 3>{i,j,k}), in1(Eigen::array<Eigen::DenseIndex, 3>{i,j,k}) + in2(Eigen::array<Eigen::DenseIndex, 3>{i,j,k}) * in3(Eigen::array<Eigen::DenseIndex, 3>{i,j,k}));
-      }
-    }
-  }
-
-  hipFree(d_in1);
-  hipFree(d_in2);
-  hipFree(d_in3);
-  hipFree(d_out);
-}
-
-void test_hip_props() {
-  Tensor<float, 1> in1(200);
-  Tensor<bool, 1> out(200);
-  in1.setRandom();
-
-  std::size_t in1_bytes = in1.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(bool);
-
-  float* d_in1;
-  bool* d_out;
-  hipMalloc((void**)(&d_in1), in1_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_in1, in1.data(), in1_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_in1(
-      d_in1, 200);
-  Eigen::TensorMap<Eigen::Tensor<bool, 1>, Eigen::Aligned> gpu_out(
-      d_out, 200);
-
-  gpu_out.device(gpu_device) = (gpu_in1.isnan)();
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost,
-                         gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 200; ++i) {
-    VERIFY_IS_EQUAL(out(i), (std::isnan)(in1(i)));
-  }
-
-  hipFree(d_in1);
-  hipFree(d_out);
-}
-
-void test_hip_reduction()
-{
-  Tensor<float, 4> in1(72,53,97,113);
-  Tensor<float, 2> out(72,97);
-  in1.setRandom();
-
-  std::size_t in1_bytes = in1.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_in1;
-  float* d_out;
-  hipMalloc((void**)(&d_in1), in1_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_in1, in1.data(), in1_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_in1(d_in1, 72,53,97,113);
-  Eigen::TensorMap<Eigen::Tensor<float, 2> > gpu_out(d_out, 72,97);
-
-  array<Eigen::DenseIndex, 2> reduction_axis;
-  reduction_axis[0] = 1;
-  reduction_axis[1] = 3;
-
-  gpu_out.device(gpu_device) = gpu_in1.maximum(reduction_axis);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 72; ++i) {
-    for (int j = 0; j < 97; ++j) {
-      float expected = 0;
-      for (int k = 0; k < 53; ++k) {
-        for (int l = 0; l < 113; ++l) {
-          expected =
-              std::max<float>(expected, in1(i, k, j, l));
-        }
-      }
-      VERIFY_IS_APPROX(out(i,j), expected);
-    }
-  }
-
-  hipFree(d_in1);
-  hipFree(d_out);
-}
-
-template<int DataLayout>
-void test_hip_contraction()
-{
-  // with these dimensions, the output has 300 * 140 elements, which is
-  // more than 30 * 1024, which is the number of threads in blocks on
-  // a 15 SM GK110 GPU
-  Tensor<float, 4, DataLayout> t_left(6, 50, 3, 31);
-  Tensor<float, 5, DataLayout> t_right(Eigen::array<Eigen::DenseIndex, 5>{3, 31, 7, 20, 1});
-  Tensor<float, 5, DataLayout> t_result(Eigen::array<Eigen::DenseIndex, 5>{6, 50, 7, 20, 1});
-
-  t_left.setRandom();
-  t_right.setRandom();
-
-  std::size_t t_left_bytes = t_left.size()  * sizeof(float);
-  std::size_t t_right_bytes = t_right.size() * sizeof(float);
-  std::size_t t_result_bytes = t_result.size() * sizeof(float);
-
-  float* d_t_left;
-  float* d_t_right;
-  float* d_t_result;
-
-  hipMalloc((void**)(&d_t_left), t_left_bytes);
-  hipMalloc((void**)(&d_t_right), t_right_bytes);
-  hipMalloc((void**)(&d_t_result), t_result_bytes);
-
-  hipMemcpy(d_t_left, t_left.data(), t_left_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_t_right, t_right.data(), t_right_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> > gpu_t_left(d_t_left, 6, 50, 3, 31);
-  Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> > gpu_t_right(d_t_right, 3, 31, 7, 20, 1);
-  Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> > gpu_t_result(d_t_result, 6, 50, 7, 20, 1);
-
-  typedef Eigen::Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> > MapXf;
-  MapXf m_left(t_left.data(), 300, 93);
-  MapXf m_right(t_right.data(), 93, 140);
-  Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result(300, 140);
-
-  typedef Tensor<float, 1>::DimensionPair DimPair;
-  Eigen::array<DimPair, 2> dims;
-  dims[0] = DimPair(2, 0);
-  dims[1] = DimPair(3, 1);
-
-  m_result = m_left * m_right;
-  gpu_t_result.device(gpu_device) = gpu_t_left.contract(gpu_t_right, dims);
-
-  hipMemcpy(t_result.data(), d_t_result, t_result_bytes, hipMemcpyDeviceToHost);
-
-  for (DenseIndex i = 0; i < t_result.size(); i++) {
-    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4f) {
-      std::cout << "mismatch detected at index " << i << ": " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
-      assert(false);
-    }
-  }
-
-  hipFree(d_t_left);
-  hipFree(d_t_right);
-  hipFree(d_t_result);
-}
-
-
-template<int DataLayout>
-void test_hip_convolution_1d()
-{
-  Tensor<float, 4, DataLayout> input(74,37,11,137);
-  Tensor<float, 1, DataLayout> kernel(4);
-  Tensor<float, 4, DataLayout> out(74,34,11,137);
-  input = input.constant(10.0f) + input.random();
-  kernel = kernel.constant(7.0f) + kernel.random();
-
-  std::size_t input_bytes = input.size() * sizeof(float);
-  std::size_t kernel_bytes = kernel.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_input;
-  float* d_kernel;
-  float* d_out;
-  hipMalloc((void**)(&d_input), input_bytes);
-  hipMalloc((void**)(&d_kernel), kernel_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_input, input.data(), input_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_kernel, kernel.data(), kernel_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> > gpu_input(d_input, 74,37,11,137);
-  Eigen::TensorMap<Eigen::Tensor<float, 1, DataLayout> > gpu_kernel(d_kernel, 4);
-  Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> > gpu_out(d_out, 74,34,11,137);
-
-  Eigen::array<Eigen::DenseIndex, 1> dims{1};
-  gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 74; ++i) {
-    for (int j = 0; j < 34; ++j) {
-      for (int k = 0; k < 11; ++k) {
-        for (int l = 0; l < 137; ++l) {
-          const float result = out(i,j,k,l);
-          const float expected = input(i,j+0,k,l) * kernel(0) + input(i,j+1,k,l) * kernel(1) +
-                                 input(i,j+2,k,l) * kernel(2) + input(i,j+3,k,l) * kernel(3);
-          VERIFY_IS_APPROX(result, expected);
-        }
-      }
-    }
-  }
-
-  hipFree(d_input);
-  hipFree(d_kernel);
-  hipFree(d_out);
-}
-
-void test_hip_convolution_inner_dim_col_major_1d()
-{
-  Tensor<float, 4, ColMajor> input(74,9,11,7);
-  Tensor<float, 1, ColMajor> kernel(4);
-  Tensor<float, 4, ColMajor> out(71,9,11,7);
-  input = input.constant(10.0f) + input.random();
-  kernel = kernel.constant(7.0f) + kernel.random();
-
-  std::size_t input_bytes = input.size() * sizeof(float);
-  std::size_t kernel_bytes = kernel.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_input;
-  float* d_kernel;
-  float* d_out;
-  hipMalloc((void**)(&d_input), input_bytes);
-  hipMalloc((void**)(&d_kernel), kernel_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_input, input.data(), input_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_kernel, kernel.data(), kernel_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4, ColMajor> > gpu_input(d_input,74,9,11,7);
-  Eigen::TensorMap<Eigen::Tensor<float, 1, ColMajor> > gpu_kernel(d_kernel,4);
-  Eigen::TensorMap<Eigen::Tensor<float, 4, ColMajor> > gpu_out(d_out,71,9,11,7);
-
-  Eigen::array<Eigen::DenseIndex, 1> dims{0};
-  gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 71; ++i) {
-    for (int j = 0; j < 9; ++j) {
-      for (int k = 0; k < 11; ++k) {
-        for (int l = 0; l < 7; ++l) {
-          const float result = out(i,j,k,l);
-          const float expected = input(i+0,j,k,l) * kernel(0) + input(i+1,j,k,l) * kernel(1) +
-                                 input(i+2,j,k,l) * kernel(2) + input(i+3,j,k,l) * kernel(3);
-          VERIFY_IS_APPROX(result, expected);
-        }
-      }
-    }
-  }
-
-  hipFree(d_input);
-  hipFree(d_kernel);
-  hipFree(d_out);
-}
-
-void test_hip_convolution_inner_dim_row_major_1d()
-{
-  Tensor<float, 4, RowMajor> input(7,9,11,74);
-  Tensor<float, 1, RowMajor> kernel(4);
-  Tensor<float, 4, RowMajor> out(7,9,11,71);
-  input = input.constant(10.0f) + input.random();
-  kernel = kernel.constant(7.0f) + kernel.random();
-
-  std::size_t input_bytes = input.size() * sizeof(float);
-  std::size_t kernel_bytes = kernel.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_input;
-  float* d_kernel;
-  float* d_out;
-  hipMalloc((void**)(&d_input), input_bytes);
-  hipMalloc((void**)(&d_kernel), kernel_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_input, input.data(), input_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_kernel, kernel.data(), kernel_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4, RowMajor> > gpu_input(d_input, 7,9,11,74);
-  Eigen::TensorMap<Eigen::Tensor<float, 1, RowMajor> > gpu_kernel(d_kernel, 4);
-  Eigen::TensorMap<Eigen::Tensor<float, 4, RowMajor> > gpu_out(d_out, 7,9,11,71);
-
-  Eigen::array<Eigen::DenseIndex, 1> dims{3};
-  gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 7; ++i) {
-    for (int j = 0; j < 9; ++j) {
-      for (int k = 0; k < 11; ++k) {
-        for (int l = 0; l < 71; ++l) {
-          const float result = out(i,j,k,l);
-          const float expected = input(i,j,k,l+0) * kernel(0) + input(i,j,k,l+1) * kernel(1) +
-                                 input(i,j,k,l+2) * kernel(2) + input(i,j,k,l+3) * kernel(3);
-          VERIFY_IS_APPROX(result, expected);
-        }
-      }
-    }
-  }
-
-  hipFree(d_input);
-  hipFree(d_kernel);
-  hipFree(d_out);
-}
-
-template<int DataLayout>
-void test_hip_convolution_2d()
-{
-  Tensor<float, 4, DataLayout> input(74,37,11,137);
-  Tensor<float, 2, DataLayout> kernel(3,4);
-  Tensor<float, 4, DataLayout> out(74,35,8,137);
-  input = input.constant(10.0f) + input.random();
-  kernel = kernel.constant(7.0f) + kernel.random();
-
-  std::size_t input_bytes = input.size() * sizeof(float);
-  std::size_t kernel_bytes = kernel.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_input;
-  float* d_kernel;
-  float* d_out;
-  hipMalloc((void**)(&d_input), input_bytes);
-  hipMalloc((void**)(&d_kernel), kernel_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_input, input.data(), input_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_kernel, kernel.data(), kernel_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> > gpu_input(d_input,74,37,11,137);
-  Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> > gpu_kernel(d_kernel,3,4);
-  Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> > gpu_out(d_out,74,35,8,137);
-
-  Eigen::array<Eigen::DenseIndex, 2> dims{1,2};
-  gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 74; ++i) {
-    for (int j = 0; j < 35; ++j) {
-      for (int k = 0; k < 8; ++k) {
-        for (int l = 0; l < 137; ++l) {
-          const float result = out(i,j,k,l);
-          const float expected = input(i,j+0,k+0,l) * kernel(0,0) +
-                                 input(i,j+1,k+0,l) * kernel(1,0) +
-                                 input(i,j+2,k+0,l) * kernel(2,0) +
-                                 input(i,j+0,k+1,l) * kernel(0,1) +
-                                 input(i,j+1,k+1,l) * kernel(1,1) +
-                                 input(i,j+2,k+1,l) * kernel(2,1) +
-                                 input(i,j+0,k+2,l) * kernel(0,2) +
-                                 input(i,j+1,k+2,l) * kernel(1,2) +
-                                 input(i,j+2,k+2,l) * kernel(2,2) +
-                                 input(i,j+0,k+3,l) * kernel(0,3) +
-                                 input(i,j+1,k+3,l) * kernel(1,3) +
-                                 input(i,j+2,k+3,l) * kernel(2,3);
-          VERIFY_IS_APPROX(result, expected);
-        }
-      }
-    }
-  }
-
-  hipFree(d_input);
-  hipFree(d_kernel);
-  hipFree(d_out);
-}
-
-template<int DataLayout>
-void test_hip_convolution_3d()
-{
-  Tensor<float, 5, DataLayout> input(Eigen::array<Eigen::DenseIndex, 5>{74,37,11,137,17});
-  Tensor<float, 3, DataLayout> kernel(3,4,2);
-  Tensor<float, 5, DataLayout> out(Eigen::array<Eigen::DenseIndex, 5>{74,35,8,136,17});
-  input = input.constant(10.0f) + input.random();
-  kernel = kernel.constant(7.0f) + kernel.random();
-
-  std::size_t input_bytes = input.size() * sizeof(float);
-  std::size_t kernel_bytes = kernel.size() * sizeof(float);
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_input;
-  float* d_kernel;
-  float* d_out;
-  hipMalloc((void**)(&d_input), input_bytes);
-  hipMalloc((void**)(&d_kernel), kernel_bytes);
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  hipMemcpy(d_input, input.data(), input_bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_kernel, kernel.data(), kernel_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;    
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> > gpu_input(d_input,74,37,11,137,17);
-  Eigen::TensorMap<Eigen::Tensor<float, 3, DataLayout> > gpu_kernel(d_kernel,3,4,2);
-  Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> > gpu_out(d_out,74,35,8,136,17);
-
-  Eigen::array<Eigen::DenseIndex, 3> dims{1,2,3};
-  gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 74; ++i) {
-    for (int j = 0; j < 35; ++j) {
-      for (int k = 0; k < 8; ++k) {
-        for (int l = 0; l < 136; ++l) {
-          for (int m = 0; m < 17; ++m) {
-            const float result = out(i,j,k,l,m);
-            const float expected = input(i,j+0,k+0,l+0,m) * kernel(0,0,0) +
-                                   input(i,j+1,k+0,l+0,m) * kernel(1,0,0) +
-                                   input(i,j+2,k+0,l+0,m) * kernel(2,0,0) +
-                                   input(i,j+0,k+1,l+0,m) * kernel(0,1,0) +
-                                   input(i,j+1,k+1,l+0,m) * kernel(1,1,0) +
-                                   input(i,j+2,k+1,l+0,m) * kernel(2,1,0) +
-                                   input(i,j+0,k+2,l+0,m) * kernel(0,2,0) +
-                                   input(i,j+1,k+2,l+0,m) * kernel(1,2,0) +
-                                   input(i,j+2,k+2,l+0,m) * kernel(2,2,0) +
-                                   input(i,j+0,k+3,l+0,m) * kernel(0,3,0) +
-                                   input(i,j+1,k+3,l+0,m) * kernel(1,3,0) +
-                                   input(i,j+2,k+3,l+0,m) * kernel(2,3,0) +
-                                   input(i,j+0,k+0,l+1,m) * kernel(0,0,1) +
-                                   input(i,j+1,k+0,l+1,m) * kernel(1,0,1) +
-                                   input(i,j+2,k+0,l+1,m) * kernel(2,0,1) +
-                                   input(i,j+0,k+1,l+1,m) * kernel(0,1,1) +
-                                   input(i,j+1,k+1,l+1,m) * kernel(1,1,1) +
-                                   input(i,j+2,k+1,l+1,m) * kernel(2,1,1) +
-                                   input(i,j+0,k+2,l+1,m) * kernel(0,2,1) +
-                                   input(i,j+1,k+2,l+1,m) * kernel(1,2,1) +
-                                   input(i,j+2,k+2,l+1,m) * kernel(2,2,1) +
-                                   input(i,j+0,k+3,l+1,m) * kernel(0,3,1) +
-                                   input(i,j+1,k+3,l+1,m) * kernel(1,3,1) +
-                                   input(i,j+2,k+3,l+1,m) * kernel(2,3,1);
-            VERIFY_IS_APPROX(result, expected);
-          }
-        }
-      }
-    }
-  }
-
-  hipFree(d_input);
-  hipFree(d_kernel);
-  hipFree(d_out);
-}
-
-
-template <typename Scalar>
-void test_hip_lgamma(const Scalar stddev)
-{
-  Tensor<Scalar, 2> in(72,97);
-  in.setRandom();
-  in *= in.constant(stddev);
-  Tensor<Scalar, 2> out(72,97);
-  out.setZero();
-
-  std::size_t bytes = in.size() * sizeof(Scalar);
-
-  Scalar* d_in;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in, in.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_in(d_in, 72, 97);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_out(d_out, 72, 97);
-
-  gpu_out.device(gpu_device) = gpu_in.lgamma();
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 72; ++i) {
-    for (int j = 0; j < 97; ++j) {
-      VERIFY_IS_APPROX(out(i,j), (std::lgamma)(in(i,j)));
-    }
-  }
-
-  hipFree(d_in);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_digamma()
-{
-  Tensor<Scalar, 1> in(7);
-  Tensor<Scalar, 1> out(7);
-  Tensor<Scalar, 1> expected_out(7);
-  out.setZero();
-
-  in(0) = Scalar(1);
-  in(1) = Scalar(1.5);
-  in(2) = Scalar(4);
-  in(3) = Scalar(-10.5);
-  in(4) = Scalar(10000.5);
-  in(5) = Scalar(0);
-  in(6) = Scalar(-1);
-
-  expected_out(0) = Scalar(-0.5772156649015329);
-  expected_out(1) = Scalar(0.03648997397857645);
-  expected_out(2) = Scalar(1.2561176684318);
-  expected_out(3) = Scalar(2.398239129535781);
-  expected_out(4) = Scalar(9.210340372392849);
-  expected_out(5) = std::numeric_limits<Scalar>::infinity();
-  expected_out(6) = std::numeric_limits<Scalar>::infinity();
-
-  std::size_t bytes = in.size() * sizeof(Scalar);
-
-  Scalar* d_in;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in, in.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in(d_in, 7);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_out(d_out, 7);
-
-  gpu_out.device(gpu_device) = gpu_in.digamma();
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 5; ++i) {
-    VERIFY_IS_APPROX(out(i), expected_out(i));
-  }
-  for (int i = 5; i < 7; ++i) {
-    VERIFY_IS_EQUAL(out(i), expected_out(i));
-  }
-
-  hipFree(d_in);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_zeta()
-{
-  Tensor<Scalar, 1> in_x(6);
-  Tensor<Scalar, 1> in_q(6);
-  Tensor<Scalar, 1> out(6);
-  Tensor<Scalar, 1> expected_out(6);
-  out.setZero();
-
-  in_x(0) = Scalar(1);
-  in_x(1) = Scalar(1.5);
-  in_x(2) = Scalar(4);
-  in_x(3) = Scalar(-10.5);
-  in_x(4) = Scalar(10000.5);
-  in_x(5) = Scalar(3);
-  
-  in_q(0) = Scalar(1.2345);
-  in_q(1) = Scalar(2);
-  in_q(2) = Scalar(1.5);
-  in_q(3) = Scalar(3);
-  in_q(4) = Scalar(1.0001);
-  in_q(5) = Scalar(-2.5);
-
-  expected_out(0) = std::numeric_limits<Scalar>::infinity();
-  expected_out(1) = Scalar(1.61237534869);
-  expected_out(2) = Scalar(0.234848505667);
-  expected_out(3) = Scalar(1.03086757337e-5);
-  expected_out(4) = Scalar(0.367879440865);
-  expected_out(5) = Scalar(0.054102025820864097);
-
-  std::size_t bytes = in_x.size() * sizeof(Scalar);
-
-  Scalar* d_in_x;
-  Scalar* d_in_q;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in_x), bytes);
-  hipMalloc((void**)(&d_in_q), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in_x, in_x.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in_q, in_q.data(), bytes, hipMemcpyHostToDevice);
-  
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_x(d_in_x, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_q(d_in_q, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_out(d_out, 6);
-
-  gpu_out.device(gpu_device) = gpu_in_x.zeta(gpu_in_q);
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  VERIFY_IS_EQUAL(out(0), expected_out(0));
-  VERIFY((std::isnan)(out(3)));
-
-  for (int i = 1; i < 6; ++i) {
-    if (i != 3) {
-      VERIFY_IS_APPROX(out(i), expected_out(i));
-    }
-  }
-
-  hipFree(d_in_x);
-  hipFree(d_in_q);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_polygamma()
-{
-  Tensor<Scalar, 1> in_x(7);
-  Tensor<Scalar, 1> in_n(7);
-  Tensor<Scalar, 1> out(7);
-  Tensor<Scalar, 1> expected_out(7);
-  out.setZero();
-
-  in_n(0) = Scalar(1);
-  in_n(1) = Scalar(1);
-  in_n(2) = Scalar(1);
-  in_n(3) = Scalar(17);
-  in_n(4) = Scalar(31);
-  in_n(5) = Scalar(28);
-  in_n(6) = Scalar(8);
-  
-  in_x(0) = Scalar(2);
-  in_x(1) = Scalar(3);
-  in_x(2) = Scalar(25.5);
-  in_x(3) = Scalar(4.7);
-  in_x(4) = Scalar(11.8);
-  in_x(5) = Scalar(17.7);
-  in_x(6) = Scalar(30.2);
-
-  expected_out(0) = Scalar(0.644934066848);
-  expected_out(1) = Scalar(0.394934066848);
-  expected_out(2) = Scalar(0.0399946696496);
-  expected_out(3) = Scalar(293.334565435);
-  expected_out(4) = Scalar(0.445487887616);
-  expected_out(5) = Scalar(-2.47810300902e-07);
-  expected_out(6) = Scalar(-8.29668781082e-09);
-
-  std::size_t bytes = in_x.size() * sizeof(Scalar);
-
-  Scalar* d_in_x;
-  Scalar* d_in_n;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in_x), bytes);
-  hipMalloc((void**)(&d_in_n), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in_x, in_x.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in_n, in_n.data(), bytes, hipMemcpyHostToDevice);
-  
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_x(d_in_x, 7);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_n(d_in_n, 7);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_out(d_out, 7);
-
-  gpu_out.device(gpu_device) = gpu_in_n.polygamma(gpu_in_x);
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 7; ++i) {
-    VERIFY_IS_APPROX(out(i), expected_out(i));
-  }
-
-  hipFree(d_in_x);
-  hipFree(d_in_n);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_igamma()
-{
-  Tensor<Scalar, 2> a(6, 6);
-  Tensor<Scalar, 2> x(6, 6);
-  Tensor<Scalar, 2> out(6, 6);
-  out.setZero();
-
-  Scalar a_s[] = {Scalar(0), Scalar(1), Scalar(1.5), Scalar(4), Scalar(0.0001), Scalar(1000.5)};
-  Scalar x_s[] = {Scalar(0), Scalar(1), Scalar(1.5), Scalar(4), Scalar(0.0001), Scalar(1000.5)};
-
-  for (int i = 0; i < 6; ++i) {
-    for (int j = 0; j < 6; ++j) {
-      a(i, j) = a_s[i];
-      x(i, j) = x_s[j];
-    }
-  }
-
-  Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
-  Scalar igamma_s[][6] = {{0.0, nan, nan, nan, nan, nan},
-                          {0.0, 0.6321205588285578, 0.7768698398515702,
-                           0.9816843611112658, 9.999500016666262e-05, 1.0},
-                          {0.0, 0.4275932955291202, 0.608374823728911,
-                           0.9539882943107686, 7.522076445089201e-07, 1.0},
-                          {0.0, 0.01898815687615381, 0.06564245437845008,
-                           0.5665298796332909, 4.166333347221828e-18, 1.0},
-                          {0.0, 0.9999780593618628, 0.9999899967080838,
-                           0.9999996219837988, 0.9991370418689945, 1.0},
-                          {0.0, 0.0, 0.0, 0.0, 0.0, 0.5042041932513908}};
-
-
-
-  std::size_t bytes = a.size() * sizeof(Scalar);
-
-  Scalar* d_a;
-  Scalar* d_x;
-  Scalar* d_out;
-  assert(hipMalloc((void**)(&d_a), bytes) == hipSuccess);
-  assert(hipMalloc((void**)(&d_x), bytes) == hipSuccess);
-  assert(hipMalloc((void**)(&d_out), bytes) == hipSuccess);
-
-  hipMemcpy(d_a, a.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_x, x.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_a(d_a, 6, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_x(d_x, 6, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_out(d_out, 6, 6);
-
-  gpu_out.device(gpu_device) = gpu_a.igamma(gpu_x);
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 6; ++i) {
-    for (int j = 0; j < 6; ++j) {
-      if ((std::isnan)(igamma_s[i][j])) {
-        VERIFY((std::isnan)(out(i, j)));
-      } else {
-        VERIFY_IS_APPROX(out(i, j), igamma_s[i][j]);
-      }
-    }
-  }
-
-  hipFree(d_a);
-  hipFree(d_x);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_igammac()
-{
-  Tensor<Scalar, 2> a(6, 6);
-  Tensor<Scalar, 2> x(6, 6);
-  Tensor<Scalar, 2> out(6, 6);
-  out.setZero();
-
-  Scalar a_s[] = {Scalar(0), Scalar(1), Scalar(1.5), Scalar(4), Scalar(0.0001), Scalar(1000.5)};
-  Scalar x_s[] = {Scalar(0), Scalar(1), Scalar(1.5), Scalar(4), Scalar(0.0001), Scalar(1000.5)};
-
-  for (int i = 0; i < 6; ++i) {
-    for (int j = 0; j < 6; ++j) {
-      a(i, j) = a_s[i];
-      x(i, j) = x_s[j];
-    }
-  }
-
-  Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
-  Scalar igammac_s[][6] = {{nan, nan, nan, nan, nan, nan},
-                           {1.0, 0.36787944117144233, 0.22313016014842982,
-                            0.018315638888734182, 0.9999000049998333, 0.0},
-                           {1.0, 0.5724067044708798, 0.3916251762710878,
-                            0.04601170568923136, 0.9999992477923555, 0.0},
-                           {1.0, 0.9810118431238462, 0.9343575456215499,
-                            0.4334701203667089, 1.0, 0.0},
-                           {1.0, 2.1940638138146658e-05, 1.0003291916285e-05,
-                            3.7801620118431334e-07, 0.0008629581310054535,
-                            0.0},
-                           {1.0, 1.0, 1.0, 1.0, 1.0, 0.49579580674813944}};
-
-  std::size_t bytes = a.size() * sizeof(Scalar);
-
-  Scalar* d_a;
-  Scalar* d_x;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_a), bytes);
-  hipMalloc((void**)(&d_x), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_a, a.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_x, x.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_a(d_a, 6, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_x(d_x, 6, 6);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_out(d_out, 6, 6);
-
-  gpu_out.device(gpu_device) = gpu_a.igammac(gpu_x);
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 6; ++i) {
-    for (int j = 0; j < 6; ++j) {
-      if ((std::isnan)(igammac_s[i][j])) {
-        VERIFY((std::isnan)(out(i, j)));
-      } else {
-        VERIFY_IS_APPROX(out(i, j), igammac_s[i][j]);
-      }
-    }
-  }
-
-  hipFree(d_a);
-  hipFree(d_x);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_erf(const Scalar stddev)
-{
-  Tensor<Scalar, 2> in(72,97);
-  in.setRandom();
-  in *= in.constant(stddev);
-  Tensor<Scalar, 2> out(72,97);
-  out.setZero();
-
-  std::size_t bytes = in.size() * sizeof(Scalar);
-
-  Scalar* d_in;
-  Scalar* d_out;
-  assert(hipMalloc((void**)(&d_in), bytes) == hipSuccess);
-  assert(hipMalloc((void**)(&d_out), bytes) == hipSuccess);
-
-  hipMemcpy(d_in, in.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_in(d_in, 72, 97);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_out(d_out, 72, 97);
-
-  gpu_out.device(gpu_device) = gpu_in.erf();
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 72; ++i) {
-    for (int j = 0; j < 97; ++j) {
-      VERIFY_IS_APPROX(out(i,j), (std::erf)(in(i,j)));
-    }
-  }
-
-  hipFree(d_in);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_erfc(const Scalar stddev)
-{
-  Tensor<Scalar, 2> in(72,97);
-  in.setRandom();
-  in *= in.constant(stddev);
-  Tensor<Scalar, 2> out(72,97);
-  out.setZero();
-
-  std::size_t bytes = in.size() * sizeof(Scalar);
-
-  Scalar* d_in;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in, in.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_in(d_in, 72, 97);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 2> > gpu_out(d_out, 72, 97);
-
-  gpu_out.device(gpu_device) = gpu_in.erfc();
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 0; i < 72; ++i) {
-    for (int j = 0; j < 97; ++j) {
-      VERIFY_IS_APPROX(out(i,j), (std::erfc)(in(i,j)));
-    }
-  }
-
-  hipFree(d_in);
-  hipFree(d_out);
-}
-
-template <typename Scalar>
-void test_hip_betainc()
-{
-  Tensor<Scalar, 1> in_x(125);
-  Tensor<Scalar, 1> in_a(125);
-  Tensor<Scalar, 1> in_b(125);
-  Tensor<Scalar, 1> out(125);
-  Tensor<Scalar, 1> expected_out(125);
-  out.setZero();
-
-  Scalar nan = std::numeric_limits<Scalar>::quiet_NaN();
-
-  Array<Scalar, 1, Dynamic> x(125);
-  Array<Scalar, 1, Dynamic> a(125);
-  Array<Scalar, 1, Dynamic> b(125);
-  Array<Scalar, 1, Dynamic> v(125);
-
-  a << 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-      0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999,
-      0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999,
-      0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379, 999.999, 999.999,
-      999.999, 999.999, 999.999, 999.999, 999.999, 999.999, 999.999, 999.999,
-      999.999, 999.999, 999.999, 999.999, 999.999, 999.999, 999.999, 999.999,
-      999.999, 999.999, 999.999, 999.999, 999.999, 999.999, 999.999;
-
-  b << 0.0, 0.0, 0.0, 0.0, 0.0, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379, 0.999,
-      0.999, 0.999, 0.999, 0.999, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379, 999.999, 999.999,
-      999.999, 999.999, 999.999, 0.0, 0.0, 0.0, 0.0, 0.0, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.999, 0.999, 0.999, 0.999, 0.999, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 999.999, 999.999, 999.999, 999.999, 999.999, 0.0, 0.0,
-      0.0, 0.0, 0.0, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379, 0.999,
-      0.999, 0.999, 0.999, 0.999, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379, 999.999, 999.999,
-      999.999, 999.999, 999.999, 0.0, 0.0, 0.0, 0.0, 0.0, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.999, 0.999, 0.999, 0.999, 0.999, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 999.999, 999.999, 999.999, 999.999, 999.999, 0.0, 0.0,
-      0.0, 0.0, 0.0, 0.03062277660168379, 0.03062277660168379,
-      0.03062277660168379, 0.03062277660168379, 0.03062277660168379, 0.999,
-      0.999, 0.999, 0.999, 0.999, 31.62177660168379, 31.62177660168379,
-      31.62177660168379, 31.62177660168379, 31.62177660168379, 999.999, 999.999,
-      999.999, 999.999, 999.999;
-
-  x << -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8,
-      1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5,
-      0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2,
-      0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1,
-      0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1,
-      -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8,
-      1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5,
-      0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2,
-      0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1, -0.1, 0.2, 0.5, 0.8, 1.1;
-
-  v << nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
-      nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
-      nan, nan, 0.47972119876364683, 0.5, 0.5202788012363533, nan, nan,
-      0.9518683957740043, 0.9789663010413743, 0.9931729188073435, nan, nan,
-      0.999995949033062, 0.9999999999993698, 0.9999999999999999, nan, nan,
-      0.9999999999999999, 0.9999999999999999, 0.9999999999999999, nan, nan, nan,
-      nan, nan, nan, nan, 0.006827081192655869, 0.0210336989586256,
-      0.04813160422599567, nan, nan, 0.20014344256217678, 0.5000000000000001,
-      0.7998565574378232, nan, nan, 0.9991401428435834, 0.999999999698403,
-      0.9999999999999999, nan, nan, 0.9999999999999999, 0.9999999999999999,
-      0.9999999999999999, nan, nan, nan, nan, nan, nan, nan,
-      1.0646600232370887e-25, 6.301722877826246e-13, 4.050966937974938e-06, nan,
-      nan, 7.864342668429763e-23, 3.015969667594166e-10, 0.0008598571564165444,
-      nan, nan, 6.031987710123844e-08, 0.5000000000000007, 0.9999999396801229,
-      nan, nan, 0.9999999999999999, 0.9999999999999999, 0.9999999999999999, nan,
-      nan, nan, nan, nan, nan, nan, 0.0, 7.029920380986636e-306,
-      2.2450728208591345e-101, nan, nan, 0.0, 9.275871147869727e-302,
-      1.2232913026152827e-97, nan, nan, 0.0, 3.0891393081932924e-252,
-      2.9303043666183996e-60, nan, nan, 2.248913486879199e-196,
-      0.5000000000004947, 0.9999999999999999, nan;
-
-  for (int i = 0; i < 125; ++i) {
-    in_x(i) = x(i);
-    in_a(i) = a(i);
-    in_b(i) = b(i);
-    expected_out(i) = v(i);
-  }
-
-  std::size_t bytes = in_x.size() * sizeof(Scalar);
-
-  Scalar* d_in_x;
-  Scalar* d_in_a;
-  Scalar* d_in_b;
-  Scalar* d_out;
-  hipMalloc((void**)(&d_in_x), bytes);
-  hipMalloc((void**)(&d_in_a), bytes);
-  hipMalloc((void**)(&d_in_b), bytes);
-  hipMalloc((void**)(&d_out), bytes);
-
-  hipMemcpy(d_in_x, in_x.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in_a, in_a.data(), bytes, hipMemcpyHostToDevice);
-  hipMemcpy(d_in_b, in_b.data(), bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_x(d_in_x, 125);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_a(d_in_a, 125);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_in_b(d_in_b, 125);
-  Eigen::TensorMap<Eigen::Tensor<Scalar, 1> > gpu_out(d_out, 125);
-
-  gpu_out.device(gpu_device) = betainc(gpu_in_a, gpu_in_b, gpu_in_x);
-
-  assert(hipMemcpyAsync(out.data(), d_out, bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  for (int i = 1; i < 125; ++i) {
-    if ((std::isnan)(expected_out(i))) {
-      VERIFY((std::isnan)(out(i)));
-    } else {
-      VERIFY_IS_APPROX(out(i), expected_out(i));
-    }
-  }
-
-  hipFree(d_in_x);
-  hipFree(d_in_a);
-  hipFree(d_in_b);
-  hipFree(d_out);
-}
-
-
-void test_cxx11_tensor_hip()
-{
-  CALL_SUBTEST(test_hip_nullary());
-  CALL_SUBTEST(test_hip_elementwise_small());
-  CALL_SUBTEST(test_hip_elementwise());
-  CALL_SUBTEST(test_hip_props());
-  CALL_SUBTEST(test_hip_reduction());
-  CALL_SUBTEST(test_hip_contraction<ColMajor>());
-  CALL_SUBTEST(test_hip_contraction<RowMajor>());
-  CALL_SUBTEST(test_hip_convolution_1d<ColMajor>());
-  CALL_SUBTEST(test_hip_convolution_1d<RowMajor>());
-  CALL_SUBTEST(test_hip_convolution_inner_dim_col_major_1d());
-  CALL_SUBTEST(test_hip_convolution_inner_dim_row_major_1d());
-  CALL_SUBTEST(test_hip_convolution_2d<ColMajor>());
-  CALL_SUBTEST(test_hip_convolution_2d<RowMajor>());
-  // The following two tests commented out due to long runtime
-  // CALL_SUBTEST(test_hip_convolution_3d<ColMajor>());
-  // CALL_SUBTEST(test_hip_convolution_3d<RowMajor>());
-
-#if __cplusplus > 199711L
-  // std::erf, std::erfc, and so on where only added in c++11. We use them
-  // as a golden reference to validate the results produced by Eigen. Therefore
-  // we can only run these tests if we use a c++11 compiler.
-
-  CALL_SUBTEST(test_hip_lgamma<float>(1.0f));
-  CALL_SUBTEST(test_hip_lgamma<float>(100.0f));
-  CALL_SUBTEST(test_hip_lgamma<float>(0.01f));
-  CALL_SUBTEST(test_hip_lgamma<float>(0.001f));
-
-  CALL_SUBTEST(test_hip_lgamma<double>(1.0));
-  CALL_SUBTEST(test_hip_lgamma<double>(100.0));
-  CALL_SUBTEST(test_hip_lgamma<double>(0.01));
-  CALL_SUBTEST(test_hip_lgamma<double>(0.001));
-
-  CALL_SUBTEST(test_hip_erf<float>(1.0f));
-  CALL_SUBTEST(test_hip_erf<float>(100.0f));
-  CALL_SUBTEST(test_hip_erf<float>(0.01f));
-  CALL_SUBTEST(test_hip_erf<float>(0.001f));
-
-  CALL_SUBTEST(test_hip_erfc<float>(1.0f));
-  // CALL_SUBTEST(test_hip_erfc<float>(100.0f)); // HIP erfc lacks precision for large inputs
-  CALL_SUBTEST(test_hip_erfc<float>(5.0f)); 
-  CALL_SUBTEST(test_hip_erfc<float>(0.01f));
-  CALL_SUBTEST(test_hip_erfc<float>(0.001f));
-
-  CALL_SUBTEST(test_hip_erf<double>(1.0));
-  CALL_SUBTEST(test_hip_erf<double>(100.0));
-  CALL_SUBTEST(test_hip_erf<double>(0.01));
-  CALL_SUBTEST(test_hip_erf<double>(0.001));
-
-  CALL_SUBTEST(test_hip_erfc<double>(1.0));
-  // CALL_SUBTEST(test_hip_erfc<double>(100.0)); // HIP erfc lacks precision for large inputs
-  CALL_SUBTEST(test_hip_erfc<double>(5.0)); 
-  CALL_SUBTEST(test_hip_erfc<double>(0.01));
-  CALL_SUBTEST(test_hip_erfc<double>(0.001));
-
-  // Following tests have functional failures on some seeds
-  // CALL_SUBTEST(test_hip_digamma<float>());
-  // CALL_SUBTEST(test_hip_digamma<double>());
-
-  // Following tests have functional failures on some seeds
-  // CALL_SUBTEST(test_hip_polygamma<float>());
-  // CALL_SUBTEST(test_hip_polygamma<double>());
-
-  // Following tests have functional failures on some seeds
-  // CALL_SUBTEST(test_hip_zeta<float>());
-  // CALL_SUBTEST(test_hip_zeta<double>());
-
-  CALL_SUBTEST(test_hip_igamma<float>());
-  CALL_SUBTEST(test_hip_igammac<float>());
-
-  CALL_SUBTEST(test_hip_igamma<double>());
-  CALL_SUBTEST(test_hip_igammac<double>());
-
-  CALL_SUBTEST(test_hip_betainc<float>());
-  CALL_SUBTEST(test_hip_betainc<double>());
-#endif
-}
diff --git a/unsupported/test/cxx11_tensor_of_float16_hip.cu b/unsupported/test/cxx11_tensor_of_float16_hip.cu
deleted file mode 100644
index 6c1a401..0000000
--- a/unsupported/test/cxx11_tensor_of_float16_hip.cu
+++ /dev/null
@@ -1,498 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_of_float16_hip
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-
-using Eigen::Tensor;
-
-template<typename>
-void test_hip_numext() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  float* d_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  bool* d_res_half = (bool*)gpu_device.allocate(num_elem * sizeof(bool));
-  bool* d_res_float = (bool*)gpu_device.allocate(num_elem * sizeof(bool));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float(
-      d_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<bool, 1>, Eigen::Aligned> gpu_res_half(
-      d_res_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<bool, 1>, Eigen::Aligned> gpu_res_float(
-      d_res_float, num_elem);
-
-  gpu_float.device(gpu_device) = gpu_float.random() - gpu_float.constant(0.5f);
-  gpu_res_float.device(gpu_device) = gpu_float.unaryExpr(Eigen::internal::scalar_isnan_op<float>());
-  gpu_res_half.device(gpu_device) = gpu_float.cast<Eigen::half>().unaryExpr(Eigen::internal::scalar_isnan_op<Eigen::half>());
-
-  Tensor<bool, 1> half_prec(num_elem);
-  Tensor<bool, 1> full_prec(num_elem);
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, num_elem*sizeof(bool));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(bool));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking numext " << i << std::endl;
-    VERIFY_IS_EQUAL(full_prec(i), half_prec(i));
-  }
-
-  gpu_device.deallocate(d_float);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-
-#ifdef EIGEN_HAS_HIP_FP16
-
-template<typename>
-void test_hip_conversion() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-  
-  float* d_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  float* d_conv = (float*)gpu_device.allocate(num_elem * sizeof(float));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float(
-      d_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_half(
-      d_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_conv(
-      d_conv, num_elem);
-
-  gpu_float.device(gpu_device) = gpu_float.random();
-  gpu_half.device(gpu_device) = gpu_float.cast<Eigen::half>();
-  gpu_conv.device(gpu_device) = gpu_half.cast<float>();
-
-  Tensor<float, 1> initial(num_elem);
-  Tensor<float, 1> final(num_elem);
-  gpu_device.memcpyDeviceToHost(initial.data(), d_float, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(final.data(), d_conv, num_elem*sizeof(float));
-
-  for (int i = 0; i < num_elem; ++i) {
-    VERIFY_IS_APPROX(initial(i), final(i));
-  }
-
-  gpu_device.deallocate(d_float);
-  gpu_device.deallocate(d_half);
-  gpu_device.deallocate(d_conv);
-}
-
-template<typename>
-void test_hip_unary() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  float* d_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_half = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float(
-      d_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_half(
-      d_res_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_float(
-      d_res_float, num_elem);
-
-  gpu_float.device(gpu_device) = gpu_float.random() - gpu_float.constant(0.5f);
-  gpu_res_float.device(gpu_device) = gpu_float.abs();
-  gpu_res_half.device(gpu_device) = gpu_float.cast<Eigen::half>().abs().cast<float>();
-
-  Tensor<float, 1> half_prec(num_elem);
-  Tensor<float, 1> full_prec(num_elem);
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(float));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking unary " << i << std::endl;
-    VERIFY_IS_APPROX(full_prec(i), half_prec(i));
-  }
-
-  gpu_device.deallocate(d_float);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-template<typename>
-void test_hip_elementwise() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  float* d_float1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_half = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float1(
-      d_float1, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float2(
-      d_float2, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_half(
-      d_res_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_float(
-      d_res_float, num_elem);
-
-  gpu_float1.device(gpu_device) = gpu_float1.random();
-  gpu_float2.device(gpu_device) = gpu_float2.random();
-  gpu_res_float.device(gpu_device) = (gpu_float1 + gpu_float2) * gpu_float1;
-  gpu_res_half.device(gpu_device) = ((gpu_float1.cast<Eigen::half>() + gpu_float2.cast<Eigen::half>()) * gpu_float1.cast<Eigen::half>()).cast<float>();
-
-  Tensor<float, 1> half_prec(num_elem);
-  Tensor<float, 1> full_prec(num_elem);
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(float));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking elemwise " << i << ": full prec = " << full_prec(i) << " vs half prec = " << half_prec(i) << std::endl;
-    VERIFY_IS_APPROX(static_cast<Eigen::half>(full_prec(i)), static_cast<Eigen::half>(half_prec(i)));
-  }
-
-  gpu_device.deallocate(d_float1);
-  gpu_device.deallocate(d_float2);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-template<typename>
-void test_hip_trancendental() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  float* d_float1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float3 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_res1_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res1_float = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res2_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res2_float = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res3_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res3_float = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float1(d_float1, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float2(d_float2, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float3(d_float3, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res1_half(d_res1_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res1_float(d_res1_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res2_half(d_res2_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res2_float(d_res2_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res3_half(d_res3_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res3_float(d_res3_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res4_half(d_res3_half, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res4_float(d_res3_float, num_elem);
-
-  gpu_float1.device(gpu_device) = gpu_float1.random() - gpu_float1.constant(0.5f);
-  gpu_float2.device(gpu_device) = gpu_float2.random() + gpu_float1.constant(0.5f);
-  gpu_float3.device(gpu_device) = gpu_float3.random();
-  gpu_res1_float.device(gpu_device) = gpu_float1.exp().cast<Eigen::half>();
-  gpu_res2_float.device(gpu_device) = gpu_float2.log().cast<Eigen::half>();
-  gpu_res3_float.device(gpu_device) = gpu_float3.log1p().cast<Eigen::half>();
-  gpu_res4_float.device(gpu_device) = gpu_float3.expm1().cast<Eigen::half>();
-
-  gpu_res1_half.device(gpu_device) = gpu_float1.cast<Eigen::half>();
-  gpu_res1_half.device(gpu_device) = gpu_res1_half.exp();
-
-  gpu_res2_half.device(gpu_device) = gpu_float2.cast<Eigen::half>();
-  gpu_res2_half.device(gpu_device) = gpu_res2_half.log();
-
-  gpu_res3_half.device(gpu_device) = gpu_float3.cast<Eigen::half>();
-  gpu_res3_half.device(gpu_device) = gpu_res3_half.log1p();
-
-  gpu_res3_half.device(gpu_device) = gpu_float3.cast<Eigen::half>();
-  gpu_res3_half.device(gpu_device) = gpu_res3_half.expm1();
-
-  Tensor<float, 1> input1(num_elem);
-  Tensor<Eigen::half, 1> half_prec1(num_elem);
-  Tensor<Eigen::half, 1> full_prec1(num_elem);
-  Tensor<float, 1> input2(num_elem);
-  Tensor<Eigen::half, 1> half_prec2(num_elem);
-  Tensor<Eigen::half, 1> full_prec2(num_elem);
-  Tensor<float, 1> input3(num_elem);
-  Tensor<Eigen::half, 1> half_prec3(num_elem);
-  Tensor<Eigen::half, 1> full_prec3(num_elem);
-  gpu_device.memcpyDeviceToHost(input1.data(), d_float1, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(input2.data(), d_float2, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(input3.data(), d_float3, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(half_prec1.data(), d_res1_half, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec1.data(), d_res1_float, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(half_prec2.data(), d_res2_half, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec2.data(), d_res2_float, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(half_prec3.data(), d_res3_half, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec3.data(), d_res3_float, num_elem*sizeof(Eigen::half));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking elemwise exp " << i << " input = " << input1(i) << " full = " << full_prec1(i) << " half = " << half_prec1(i) << std::endl;
-    VERIFY_IS_APPROX(full_prec1(i), half_prec1(i));
-  }
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking elemwise log " << i << " input = " << input2(i) << " full = " << full_prec2(i) << " half = " << half_prec2(i) << std::endl;
-    if(std::abs(input2(i)-1.f)<0.05f) // log lacks accurary nearby 1
-      VERIFY_IS_APPROX(full_prec2(i)+Eigen::half(0.1f), half_prec2(i)+Eigen::half(0.1f));
-    else
-      VERIFY_IS_APPROX(full_prec2(i), half_prec2(i));
-  }
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking elemwise plog1 " << i << " input = " << input3(i) << " full = " << full_prec3(i) << " half = " << half_prec3(i) << std::endl;
-    VERIFY_IS_APPROX(full_prec3(i), half_prec3(i));
-  }
-  gpu_device.deallocate(d_float1);
-  gpu_device.deallocate(d_float2);
-  gpu_device.deallocate(d_float3);
-  gpu_device.deallocate(d_res1_half);
-  gpu_device.deallocate(d_res1_float);
-  gpu_device.deallocate(d_res2_half);
-  gpu_device.deallocate(d_res2_float);
-  gpu_device.deallocate(d_res3_float);
-  gpu_device.deallocate(d_res3_half);
-}
-
-template<typename>
-void test_hip_contractions() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int rows = 23;
-  int cols = 23;
-  int num_elem = rows*cols;
-
-  float* d_float1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_res_half = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-  Eigen::half* d_res_float = (Eigen::half*)gpu_device.allocate(num_elem * sizeof(Eigen::half));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float1(
-      d_float1, rows, cols);
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float2(
-      d_float2, rows, cols);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 2>, Eigen::Aligned> gpu_res_half(
-      d_res_half, rows, cols);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 2>, Eigen::Aligned> gpu_res_float(
-      d_res_float, rows, cols);
-
-  gpu_float1.device(gpu_device) = gpu_float1.random() - gpu_float1.constant(0.5f);
-  gpu_float2.device(gpu_device) = gpu_float2.random() - gpu_float2.constant(0.5f);
-
-  typedef Tensor<float, 2>::DimensionPair DimPair;
-  Eigen::array<DimPair, 1> dims(DimPair(1, 0));
-  gpu_res_float.device(gpu_device) = gpu_float1.contract(gpu_float2, dims).cast<Eigen::half>();
-  gpu_res_half.device(gpu_device) = gpu_float1.cast<Eigen::half>().contract(gpu_float2.cast<Eigen::half>(), dims);
-
-  Tensor<Eigen::half, 2> half_prec(rows, cols);
-  Tensor<Eigen::half, 2> full_prec(rows, cols);
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, num_elem*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(Eigen::half));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < rows; ++i) {
-    for (int j = 0; j < cols; ++j) {
-      std::cout << "Checking contract " << i << " " << j << full_prec(i, j) << " " << half_prec(i, j) << std::endl;
-      if (numext::abs(full_prec(i, j) - half_prec(i, j)) > Eigen::half(1e-2f)) {
-        VERIFY_IS_APPROX(full_prec(i, j), half_prec(i, j));
-      }
-    }
-  }
-
-  gpu_device.deallocate(d_float1);
-  gpu_device.deallocate(d_float2);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-template<typename>
-void test_hip_reductions(int size1, int size2, int redux) {
-
-   std::cout << "Reducing " << size1 << " by " << size2
-             << " tensor along dim " << redux << std::endl; 
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = size1*size2;
-  int result_size = (redux == 1 ? size1 : size2);
-
-  float* d_float1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_res_half = (Eigen::half*)gpu_device.allocate(result_size * sizeof(Eigen::half));
-  Eigen::half* d_res_float = (Eigen::half*)gpu_device.allocate(result_size * sizeof(Eigen::half));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float1(
-      d_float1, size1, size2);
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float2(
-      d_float2, size1, size2);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res_half(
-      d_res_half, result_size);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 1>, Eigen::Aligned> gpu_res_float(
-      d_res_float, result_size);
-
-  gpu_float1.device(gpu_device) = gpu_float1.random() * 2.0f;
-  gpu_float2.device(gpu_device) = gpu_float2.random() * 2.0f;
-
-  Eigen::array<int, 1> redux_dim(redux);
-  gpu_res_float.device(gpu_device) = gpu_float1.sum(redux_dim).cast<Eigen::half>();
-  gpu_res_half.device(gpu_device) = gpu_float1.cast<Eigen::half>().sum(redux_dim);
-
-  Tensor<Eigen::half, 1> half_prec(result_size);
-  Tensor<Eigen::half, 1> full_prec(result_size);
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, result_size*sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, result_size*sizeof(Eigen::half));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < result_size; ++i) {
-    std::cout << "EXPECTED " << full_prec(i) << " GOT " << half_prec(i) << std::endl;
-    VERIFY_IS_APPROX(full_prec(i), half_prec(i));
-  }
-
-  gpu_device.deallocate(d_float1);
-  gpu_device.deallocate(d_float2);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-template<typename>
-void test_hip_reductions() {
-  test_hip_reductions<void>(13, 13, 0);
-  test_hip_reductions<void>(13, 13, 1);
-
-  test_hip_reductions<void>(35, 36, 0);
-  test_hip_reductions<void>(35, 36, 1);
-
-  test_hip_reductions<void>(36, 35, 0);
-  test_hip_reductions<void>(36, 35, 1);
-}
-
-template<typename>
-void test_hip_full_reductions() {
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int size = 13;
-  int num_elem = size*size;
-
-  float* d_float1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_float2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  Eigen::half* d_res_half = (Eigen::half*)gpu_device.allocate(1 * sizeof(Eigen::half));
-  Eigen::half* d_res_float = (Eigen::half*)gpu_device.allocate(1 * sizeof(Eigen::half));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float1(
-      d_float1, size, size);
-  Eigen::TensorMap<Eigen::Tensor<float, 2>, Eigen::Aligned> gpu_float2(
-      d_float2, size, size);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 0>, Eigen::Aligned> gpu_res_half(
-      d_res_half);
-  Eigen::TensorMap<Eigen::Tensor<Eigen::half, 0>, Eigen::Aligned> gpu_res_float(
-      d_res_float);
-
-  gpu_float1.device(gpu_device) = gpu_float1.random();
-  gpu_float2.device(gpu_device) = gpu_float2.random();
-
-  gpu_res_float.device(gpu_device) = gpu_float1.sum().cast<Eigen::half>();
-  gpu_res_half.device(gpu_device) = gpu_float1.cast<Eigen::half>().sum();
-
-  Tensor<Eigen::half, 0> half_prec;
-  Tensor<Eigen::half, 0> full_prec;
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, sizeof(Eigen::half));
-  gpu_device.synchronize();
-
-  VERIFY_IS_APPROX(full_prec(), half_prec());
-
-  gpu_res_float.device(gpu_device) = gpu_float1.maximum().cast<Eigen::half>();
-  gpu_res_half.device(gpu_device) = gpu_float1.cast<Eigen::half>().maximum();
-  gpu_device.memcpyDeviceToHost(half_prec.data(), d_res_half, sizeof(Eigen::half));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, sizeof(Eigen::half));
-  gpu_device.synchronize();
-
-  VERIFY_IS_APPROX(full_prec(), half_prec());
-
-  gpu_device.deallocate(d_float1);
-  gpu_device.deallocate(d_float2);
-  gpu_device.deallocate(d_res_half);
-  gpu_device.deallocate(d_res_float);
-}
-
-template<typename>
-void test_hip_forced_evals() {
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-  int num_elem = 101;
-
-  float* d_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_half1 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_half2 = (float*)gpu_device.allocate(num_elem * sizeof(float));
-  float* d_res_float = (float*)gpu_device.allocate(num_elem * sizeof(float));
-
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_float(
-      d_float, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_half1(
-      d_res_half1, num_elem);
- Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Unaligned> gpu_res_half2(
-      d_res_half2, num_elem);
-  Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_res_float(
-      d_res_float, num_elem);
-
-  Eigen::array<int, 1> no_bcast;
-  no_bcast[0] = 1;
-
-  gpu_float.device(gpu_device) = gpu_float.random() - gpu_float.constant(0.5f);
-  gpu_res_float.device(gpu_device) = gpu_float.abs();
-  gpu_res_half1.device(gpu_device) = gpu_float.cast<Eigen::half>().abs().eval().cast<float>();
-  gpu_res_half2.device(gpu_device) = gpu_float.cast<Eigen::half>().abs().broadcast(no_bcast).eval().cast<float>();
-
-  Tensor<float, 1> half_prec1(num_elem);
-  Tensor<float, 1> half_prec2(num_elem);
-  Tensor<float, 1> full_prec(num_elem);
-  gpu_device.memcpyDeviceToHost(half_prec1.data(), d_res_half1, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(half_prec2.data(), d_res_half1, num_elem*sizeof(float));
-  gpu_device.memcpyDeviceToHost(full_prec.data(), d_res_float, num_elem*sizeof(float));
-  gpu_device.synchronize();
-
-  for (int i = 0; i < num_elem; ++i) {
-    std::cout << "Checking forced eval " << i << full_prec(i) << " vs " << half_prec1(i) << " vs " << half_prec2(i) << std::endl;
-    VERIFY_IS_APPROX(full_prec(i), half_prec1(i));
-    VERIFY_IS_APPROX(full_prec(i), half_prec2(i));
-  }
-
-  gpu_device.deallocate(d_float);
-  gpu_device.deallocate(d_res_half1);
-  gpu_device.deallocate(d_res_half2);
-  gpu_device.deallocate(d_res_float);
-}
-#endif
-
-
-void test_cxx11_tensor_of_float16_hip()
-{
-  CALL_SUBTEST(test_hip_numext<void>());
-
-#ifdef EIGEN_HAS_HIP_FP16
-  CALL_SUBTEST(test_hip_conversion<void>());
-  CALL_SUBTEST(test_hip_unary<void>());
-  CALL_SUBTEST(test_hip_elementwise<void>());
-  CALL_SUBTEST(test_hip_trancendental<void>());
-  CALL_SUBTEST(test_hip_contractions<void>());
-  CALL_SUBTEST(test_hip_reductions<void>());
-  CALL_SUBTEST(test_hip_full_reductions<void>());
-  CALL_SUBTEST(test_hip_forced_evals<void>());
-#else
-  std::cout << "Half floats are not supported by this version of hip: skipping the test" << std::endl;
-#endif
-}
diff --git a/unsupported/test/cxx11_tensor_random_hip.cu b/unsupported/test/cxx11_tensor_random_hip.cu
deleted file mode 100644
index 7d7e72c..0000000
--- a/unsupported/test/cxx11_tensor_random_hip.cu
+++ /dev/null
@@ -1,85 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_random_hip
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <Eigen/CXX11/Tensor>
-
-
-void test_hip_random_uniform()
-{
-  Tensor<float, 2> out(72,97);
-  out.setZero();
-
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_out;
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2> > gpu_out(d_out, 72,97);
-
-  gpu_out.device(gpu_device) = gpu_out.random();
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-
-  // For now we just check thes code doesn't crash.
-  // TODO: come up with a valid test of randomness
-}
-
-
-void test_hip_random_normal()
-{
-  Tensor<float, 2> out(72,97);
-  out.setZero();
-
-  std::size_t out_bytes = out.size() * sizeof(float);
-
-  float* d_out;
-  hipMalloc((void**)(&d_out), out_bytes);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 2> > gpu_out(d_out, 72,97);
-
-  Eigen::internal::NormalRandomGenerator<float> gen(true);
-  gpu_out.device(gpu_device) = gpu_out.random(gen);
-
-  assert(hipMemcpyAsync(out.data(), d_out, out_bytes, hipMemcpyDeviceToHost, gpu_device.stream()) == hipSuccess);
-  assert(hipStreamSynchronize(gpu_device.stream()) == hipSuccess);
-}
-
-static void test_complex()
-{
-  Tensor<std::complex<float>, 1> vec(6);
-  vec.setRandom();
-
-  // Fixme: we should check that the generated numbers follow a uniform
-  // distribution instead.
-  for (int i = 1; i < 6; ++i) {
-    VERIFY_IS_NOT_EQUAL(vec(i), vec(i-1));
-  }
-}
-
-
-void test_cxx11_tensor_random_hip()
-{
-  CALL_SUBTEST(test_hip_random_uniform());
-  CALL_SUBTEST(test_hip_random_normal());
-  CALL_SUBTEST(test_complex());
-}
diff --git a/unsupported/test/cxx11_tensor_reduction_hip.cu b/unsupported/test/cxx11_tensor_reduction_hip.cu
deleted file mode 100644
index c5aad05..0000000
--- a/unsupported/test/cxx11_tensor_reduction_hip.cu
+++ /dev/null
@@ -1,154 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2015 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_reduction_hip
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-
-template<typename Type, int DataLayout>
-static void test_full_reductions() {
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  const int num_rows = internal::random<int>(1024, 5*1024);
-  const int num_cols = internal::random<int>(1024, 5*1024);
-
-  Tensor<Type, 2, DataLayout> in(num_rows, num_cols);
-  in.setRandom();
-
-  Tensor<Type, 0, DataLayout> full_redux;
-  full_redux = in.sum();
-
-  std::size_t in_bytes = in.size() * sizeof(Type);
-  std::size_t out_bytes = full_redux.size() * sizeof(Type);
-  Type* gpu_in_ptr = static_cast<Type*>(gpu_device.allocate(in_bytes));
-  Type* gpu_out_ptr = static_cast<Type*>(gpu_device.allocate(out_bytes));
-  gpu_device.memcpyHostToDevice(gpu_in_ptr, in.data(), in_bytes);
-
-  TensorMap<Tensor<Type, 2, DataLayout> > in_gpu(gpu_in_ptr, num_rows, num_cols);
-  TensorMap<Tensor<Type, 0, DataLayout> > out_gpu(gpu_out_ptr);
-
-  out_gpu.device(gpu_device) = in_gpu.sum();
-
-  Tensor<Type, 0, DataLayout> full_redux_gpu;
-  gpu_device.memcpyDeviceToHost(full_redux_gpu.data(), gpu_out_ptr, out_bytes);
-  gpu_device.synchronize();
-
-  // Check that the CPU and GPU reductions return the same result.
-  VERIFY_IS_APPROX(full_redux(), full_redux_gpu());
-
-  gpu_device.deallocate(gpu_in_ptr);
-  gpu_device.deallocate(gpu_out_ptr);
-}
-
-template<typename Type, int DataLayout>
-static void test_first_dim_reductions() {
-  int dim_x = 33;
-  int dim_y = 1;
-  int dim_z = 128;
-
-  Tensor<Type, 3, DataLayout> in(dim_x, dim_y, dim_z);
-  in.setRandom();
-
-  Eigen::array<int, 1> red_axis;
-  red_axis[0] = 0;
-  Tensor<Type, 2, DataLayout> redux = in.sum(red_axis);
-
-  // Create device
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice dev(&stream);
-  
-  // Create data(T)
-  Type* in_data = (Type*)dev.allocate(dim_x*dim_y*dim_z*sizeof(Type));
-  Type* out_data = (Type*)dev.allocate(dim_z*dim_y*sizeof(Type));
-  Eigen::TensorMap<Eigen::Tensor<Type, 3, DataLayout> > gpu_in(in_data, dim_x, dim_y, dim_z);
-  Eigen::TensorMap<Eigen::Tensor<Type, 2, DataLayout> > gpu_out(out_data, dim_y, dim_z);
-  
-  // Perform operation
-  dev.memcpyHostToDevice(in_data, in.data(), in.size()*sizeof(Type));
-  gpu_out.device(dev) = gpu_in.sum(red_axis);
-  gpu_out.device(dev) += gpu_in.sum(red_axis);
-  Tensor<Type, 2, DataLayout> redux_gpu(dim_y, dim_z);
-  dev.memcpyDeviceToHost(redux_gpu.data(), out_data, gpu_out.size()*sizeof(Type));
-  dev.synchronize();
-
-  // Check that the CPU and GPU reductions return the same result.
-  for (int i = 0; i < gpu_out.size(); ++i) {
-    VERIFY_IS_APPROX(2*redux(i), redux_gpu(i));
-  }
-
-  dev.deallocate(in_data);
-  dev.deallocate(out_data);
-}
-
-template<typename Type, int DataLayout>
-static void test_last_dim_reductions() {
-  int dim_x = 128;
-  int dim_y = 1;
-  int dim_z = 33;
-
-  Tensor<Type, 3, DataLayout> in(dim_x, dim_y, dim_z);
-  in.setRandom();
-
-  Eigen::array<int, 1> red_axis;
-  red_axis[0] = 2;
-  Tensor<Type, 2, DataLayout> redux = in.sum(red_axis);
-
-  // Create device
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice dev(&stream);
-  
-  // Create data
-  Type* in_data = (Type*)dev.allocate(dim_x*dim_y*dim_z*sizeof(Type));
-  Type* out_data = (Type*)dev.allocate(dim_x*dim_y*sizeof(Type));
-  Eigen::TensorMap<Eigen::Tensor<Type, 3, DataLayout> > gpu_in(in_data, dim_x, dim_y, dim_z);
-  Eigen::TensorMap<Eigen::Tensor<Type, 2, DataLayout> > gpu_out(out_data, dim_x, dim_y);
-  
-  // Perform operation
-  dev.memcpyHostToDevice(in_data, in.data(), in.size()*sizeof(Type));
-  gpu_out.device(dev) = gpu_in.sum(red_axis);
-  gpu_out.device(dev) += gpu_in.sum(red_axis);
-  Tensor<Type, 2, DataLayout> redux_gpu(dim_x, dim_y);
-  dev.memcpyDeviceToHost(redux_gpu.data(), out_data, gpu_out.size()*sizeof(Type));
-  dev.synchronize();
-
-  // Check that the CPU and GPU reductions return the same result.
-  for (int i = 0; i < gpu_out.size(); ++i) {
-    VERIFY_IS_APPROX(2*redux(i), redux_gpu(i));
-  }
-
-  dev.deallocate(in_data);
-  dev.deallocate(out_data);
-}
-
-
-void test_cxx11_tensor_reduction_hip() {
-  CALL_SUBTEST((test_full_reductions<float, ColMajor>()));
-  CALL_SUBTEST((test_full_reductions<double, ColMajor>()));
-  CALL_SUBTEST((test_full_reductions<float, RowMajor>()));
-  CALL_SUBTEST((test_full_reductions<double, RowMajor>()));
-  
-  CALL_SUBTEST((test_first_dim_reductions<float, ColMajor>()));
-  CALL_SUBTEST((test_first_dim_reductions<double, ColMajor>()));
-  CALL_SUBTEST((test_first_dim_reductions<float, RowMajor>()));
-// Outer reductions of doubles aren't supported just yet.  					      
-//  CALL_SUBTEST((test_first_dim_reductions<double, RowMajor>()))
-
-  CALL_SUBTEST((test_last_dim_reductions<float, ColMajor>()));
-// Outer reductions of doubles aren't supported just yet.  					      
-//  CALL_SUBTEST((test_last_dim_reductions<double, ColMajor>()));
-  CALL_SUBTEST((test_last_dim_reductions<float, RowMajor>()));
-  CALL_SUBTEST((test_last_dim_reductions<double, RowMajor>()));
-}
diff --git a/unsupported/test/cxx11_tensor_scan_hip.cu b/unsupported/test/cxx11_tensor_scan_hip.cu
deleted file mode 100644
index f4c4f59..0000000
--- a/unsupported/test/cxx11_tensor_scan_hip.cu
+++ /dev/null
@@ -1,76 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra.
-//
-// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
-//
-// This Source Code Form is subject to the terms of the Mozilla
-// Public License v. 2.0. If a copy of the MPL was not distributed
-// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#define EIGEN_TEST_NO_LONGDOUBLE
-#define EIGEN_TEST_NO_COMPLEX
-#define EIGEN_TEST_FUNC cxx11_tensor_scan_hip
-#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
-#define EIGEN_USE_GPU
-
-#include "main.h"
-#include <unsupported/Eigen/CXX11/Tensor>
-
-using Eigen::Tensor;
-typedef Tensor<float, 1>::DimensionPair DimPair;
-
-template<int DataLayout>
-void test_hip_cumsum(int m_size, int k_size, int n_size)
-{
-  std::cout << "Testing for (" << m_size << "," << k_size << "," << n_size << ")" << std::endl;
-  Tensor<float, 3, DataLayout> t_input(m_size, k_size, n_size);
-  Tensor<float, 3, DataLayout> t_result(m_size, k_size, n_size);
-  Tensor<float, 3, DataLayout> t_result_gpu(m_size, k_size, n_size);
-
-  t_input.setRandom();
-
-  std::size_t t_input_bytes = t_input.size()  * sizeof(float);
-  std::size_t t_result_bytes = t_result.size() * sizeof(float);
-
-  float* d_t_input;
-  float* d_t_result;
-
-  hipMalloc((void**)(&d_t_input), t_input_bytes);
-  hipMalloc((void**)(&d_t_result), t_result_bytes);
-
-  hipMemcpy(d_t_input, t_input.data(), t_input_bytes, hipMemcpyHostToDevice);
-
-  Eigen::HipStreamDevice stream;
-  Eigen::GpuDevice gpu_device(&stream);
-
-  Eigen::TensorMap<Eigen::Tensor<float, 3, DataLayout> >
-      gpu_t_input(d_t_input, Eigen::array<int, 3>(m_size, k_size, n_size));
-  Eigen::TensorMap<Eigen::Tensor<float, 3, DataLayout> >
-      gpu_t_result(d_t_result, Eigen::array<int, 3>(m_size, k_size, n_size));
-
-  gpu_t_result.device(gpu_device) = gpu_t_input.cumsum(1);
-  t_result = t_input.cumsum(1);
-
-  hipMemcpy(t_result_gpu.data(), d_t_result, t_result_bytes, hipMemcpyDeviceToHost);
-  for (DenseIndex i = 0; i < t_result.size(); i++) {
-    if (fabs(t_result(i) - t_result_gpu(i)) < 1e-4f) {
-      continue;
-    }
-    if (Eigen::internal::isApprox(t_result(i), t_result_gpu(i), 1e-4f)) {
-      continue;
-    }
-    std::cout << "mismatch detected at index " << i << ": " << t_result(i)
-              << " vs " <<  t_result_gpu(i) << std::endl;
-    assert(false);
-  }
-
-  hipFree((void*)d_t_input);
-  hipFree((void*)d_t_result);
-}
-
-
-void test_cxx11_tensor_scan_hip()
-{
-  CALL_SUBTEST(test_hip_cumsum<ColMajor>(128, 128, 128));
-  CALL_SUBTEST(test_hip_cumsum<RowMajor>(128, 128, 128));
-}