| 135 | }; |
| 136 | |
| 137 | bool RelayoutForwardImpl::Param::try_copy_last_contig() { |
| 138 | if (m_dst.layout.dtype.is_low_bit()) |
| 139 | return false; |
| 140 | //! check if the last stride is contiguous |
| 141 | auto gcd = [](size_t a, size_t b) { |
| 142 | if (a > b) |
| 143 | std::swap(a, b); |
| 144 | size_t c; |
| 145 | while (a != 0) { |
| 146 | c = a; |
| 147 | a = b % a; |
| 148 | b = c; |
| 149 | } |
| 150 | return b; |
| 151 | }; |
| 152 | auto has_negative_stride = [](const TensorLayout& layout) { |
| 153 | rep(i, layout.ndim) { |
| 154 | if (layout.stride[i] < 0) |
| 155 | return true; |
| 156 | } |
| 157 | return false; |
| 158 | }; |
| 159 | |
| 160 | TensorLayout lsrc = m_src.layout, ldst = m_dst.layout; |
| 161 | if (lsrc.stride[lsrc.ndim - 1] == 1 && ldst.stride[ldst.ndim - 1] == 1 && |
| 162 | !has_negative_stride(lsrc) && !has_negative_stride(ldst)) { |
| 163 | size_t contiguous_size = |
| 164 | gcd(lsrc.shape[lsrc.ndim - 1], ldst.shape[ldst.ndim - 1]); |
| 165 | // FIXME: disable copy_last_contiguous when contiguous_size < 32 due to |
| 166 | // performance issue |
| 167 | if (contiguous_size >= 32) { |
| 168 | copy_last_contiguous(m_dst, m_src, contiguous_size, m_opr->stream()); |
| 169 | return true; |
| 170 | } |
| 171 | } |
| 172 | return false; |
| 173 | } |
| 174 | |
| 175 | void RelayoutForwardImpl::Param::copy_general() { |
| 176 | copy_noncontig_general(m_dst, m_src, m_opr->stream()); |