| 36 | */ |
| 37 | template <typename T, size_t M, size_t N, size_t P> |
| 38 | Matrix<M, P, T> MultiplyWithClangVectors(const Matrix<M, N, T>& lhs, |
| 39 | const Matrix<N, P, T>& rhs) { |
| 40 | // The rearrangement of the matrix multiplication algorithm here allows us to |
| 41 | // avoid reducing vectors to scalar stores. Instead we compute the partial |
| 42 | // result for each (result) column as a vector, accumulate partial results |
| 43 | // there, and then store the resulting row with a single vector store. |
| 44 | // |
| 45 | // This implementation only works if your columns (or rows, if you restructure |
| 46 | // this and the data to work in row-major order) fit within your vector |
| 47 | // registers. If you have larger data, you can tile the algorithm to fit the |
| 48 | // vector size. |
| 49 | // |
| 50 | // See https://mbernste.github.io/posts/matrix_vector_mult/ for a more |
| 51 | // thorough explanation. |
| 52 | typedef T Vec __attribute__((__vector_size__(M * sizeof(T)))); |
| 53 | Matrix<M, P, T> result; |
| 54 | for (auto result_column_index = 0U; result_column_index < P; |
| 55 | result_column_index++) { |
| 56 | Vec result_column = {}; |
| 57 | for (auto lhs_column_index = 0U; lhs_column_index < N; lhs_column_index++) { |
| 58 | auto c = lhs.column(lhs_column_index); |
| 59 | Vec lhs_column = *reinterpret_cast<const Vec*>(c.data()); |
| 60 | result_column += lhs_column * rhs[lhs_column_index, result_column_index]; |
| 61 | } |
| 62 | *reinterpret_cast<Vec*>(result.column(result_column_index).data()) = |
| 63 | result_column; |
| 64 | } |
| 65 | return result; |
| 66 | } |
| 67 | |
| 68 | } // namespace samples::vectorization |
no test coverage detected