openGPMP
Open Source Mathematics Package
mtx_sse2_vec_i32.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  *
3  * Project
4  * _____ _____ __ __ _____
5  * / ____| __ \| \/ | __ \
6  * ___ _ __ ___ _ __ | | __| |__) | \ / | |__) |
7  * / _ \| '_ \ / _ \ '_ \| | |_ | ___/| |\/| | ___/
8  *| (_) | |_) | __/ | | | |__| | | | | | | |
9  * \___/| .__/ \___|_| |_|\_____|_| |_| |_|_|
10  * | |
11  * |_|
12  *
13  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
14  *
15  * This software is licensed as described in the file LICENSE, which
16  * you should have received as part of this distribution. The terms
17  * among other details are referenced in the official documentation
18  * seen here : https://akielaries.github.io/openGPMP/ along with
19  * important files seen in this project.
20  *
21  * You may opt to use, copy, modify, merge, publish, distribute
22  * and/or sell copies of the Software, and permit persons to whom
23  * the Software is furnished to do so, under the terms of the
24  * LICENSE file. As this is an Open Source effort, all implementations
25  * must be of the same methodology.
26  *
27  *
28  *
29  * This software is distributed on an AS IS basis, WITHOUT
30  * WARRANTY OF ANY KIND, either express or implied.
31  *
32  ************************************************************************/
33 #include <cassert>
34 #include <cstddef>
35 #include <cstdint>
36 #include <iostream>
37 #include <openGPMP/linalg/mtx.hpp>
38 #include <vector>
39 
40 #if defined(__x86_64__) || defined(__amd64__) || defined(__amd64)
41 
42 /************************************************************************
43  *
44  * Matrix Operations for SSE ISA
45  *
46  ************************************************************************/
47 #if defined(__SSE2__)
48 // SSE2
49 #include <emmintrin.h>
50 #include <smmintrin.h>
51 
52 /************************************************************************
53  *
54  * Matrix Operations on vector<vector>
55  *
56  ************************************************************************/
57 void gpmp::linalg::Mtx::mtx_add(const std::vector<std::vector<int>> &A,
58  const std::vector<std::vector<int>> &B,
59  std::vector<std::vector<int>> &C) {
60  const int rows = A.size();
61  const int cols = A[0].size();
62 
63  if (rows > 4) { // Check for at least 4x4 matrices for SSE
64  for (int i = 0; i < rows; ++i) {
65  int j = 0;
66  // requires at least size 4x4 matrices for SSE
67  for (; j < cols - 3; j += 4) {
68  // load 4 elements from A, B, and C matrices using SSE
69  __m128i a = _mm_loadu_si128(
70  reinterpret_cast<const __m128i *>(&A[i][j]));
71  __m128i b = _mm_loadu_si128(
72  reinterpret_cast<const __m128i *>(&B[i][j]));
73  __m128i c = _mm_loadu_si128(
74  reinterpret_cast<const __m128i *>(&C[i][j]));
75 
76  // perform vectorized addition (SSE2)
77  c = _mm_add_epi32(a, b);
78 
79  // store the result back to the C matrix
80  _mm_storeu_si128(reinterpret_cast<__m128i *>(&C[i][j]), c);
81  }
82 
83  // handle the remaining elements that are not multiples of 4
84  for (; j < cols; ++j) {
85  C[i][j] = A[i][j] + B[i][j];
86  }
87  }
88  } else {
89  // use standard matrix addition for smaller matrices
90  std_mtx_add(A, B, C);
91  }
92 }
93 
94 void gpmp::linalg::Mtx::mtx_sub(const std::vector<std::vector<int>> &A,
95  const std::vector<std::vector<int>> &B,
96  std::vector<std::vector<int>> &C) {
97  const int rows = A.size();
98  const int cols = A[0].size();
99 
100  for (int i = 0; i < rows; ++i) {
101  int j = 0;
102  // requires at least size 4x4 matrices for SSE2
103  for (; j < cols - 3; j += 4) {
104  // load 4 elements from A, B, and C matrices using SSE2
105  __m128i a =
106  _mm_loadu_si128(reinterpret_cast<const __m128i *>(&A[i][j]));
107  __m128i b =
108  _mm_loadu_si128(reinterpret_cast<const __m128i *>(&B[i][j]));
109  __m128i c =
110  _mm_loadu_si128(reinterpret_cast<const __m128i *>(&C[i][j]));
111 
112  // perform vectorized subtraction
113  c = _mm_sub_epi32(a, b);
114 
115  // store the result back to the C matrix
116  _mm_storeu_si128(reinterpret_cast<__m128i *>(&C[i][j]), c);
117  }
118 
119  // handle the remaining elements that are not multiples of 4
120  for (; j < cols; ++j) {
121  C[i][j] = A[i][j] - B[i][j];
122  }
123  }
124 }
125 
126 void gpmp::linalg::Mtx::mtx_mult(const std::vector<std::vector<int>> &A,
127  const std::vector<std::vector<int>> &B,
128  std::vector<std::vector<int>> &C) {
129  const int rows_a = A.size();
130  const int cols_a = A[0].size();
131  const int cols_b = B[0].size();
132 
133  for (int i = 0; i < rows_a; ++i) {
134  for (int j = 0; j < cols_b; j += 4) {
135  // initialize a vector of zeros for the result
136  __m128i c = _mm_setzero_si128();
137 
138  for (int k = 0; k < cols_a; ++k) {
139  // load 4 elements from matrices A and B using SSE2
140  __m128i a = _mm_set1_epi32(A[i][k]);
141  __m128i b = _mm_loadu_si128(
142  reinterpret_cast<const __m128i *>(&B[k][j]));
143 
144  // perform vectorized multiplication
145  __m128i prod = _mm_mullo_epi32(a, b);
146 
147  // perform vectorized addition
148  c = _mm_add_epi32(c, prod);
149  }
150 
151  // store the result back to the C matrix
152  _mm_storeu_si128(reinterpret_cast<__m128i *>(&C[i][j]), c);
153  }
154 
155  // handle the remaining elements that are not multiples of 4
156  for (int j = cols_b - cols_b % 4; j < cols_b; ++j) {
157  int sum = 0;
158 
159  for (int k = 0; k < cols_a; ++k) {
160  sum += A[i][k] * B[k][j];
161  }
162 
163  C[i][j] = sum;
164  }
165  }
166 }
167 
168 // transpose matrices of type int using Intel intrinsics
169 void gpmp::linalg::Mtx::mtx_tpose(std::vector<std::vector<int>> &matrix) {
170  const int rows = matrix.size();
171  const int cols = matrix[0].size();
172 
173  for (int i = 0; i < rows; i += 4) {
174  for (int j = i; j < cols; j += 4) {
175  __m128i row1 = _mm_loadu_si128(
176  reinterpret_cast<const __m128i *>(&matrix[i][j]));
177  __m128i row2 = _mm_loadu_si128(
178  reinterpret_cast<const __m128i *>(&matrix[i + 1][j]));
179  __m128i row3 = _mm_loadu_si128(
180  reinterpret_cast<const __m128i *>(&matrix[i + 2][j]));
181  __m128i row4 = _mm_loadu_si128(
182  reinterpret_cast<const __m128i *>(&matrix[i + 3][j]));
183 
184  __m128i tmp1, tmp2, tmp3, tmp4;
185 
186  // transpose 4x4 submatrix
187  tmp1 = _mm_unpacklo_epi32(row1, row2);
188  tmp2 = _mm_unpacklo_epi32(row3, row4);
189  tmp3 = _mm_unpackhi_epi32(row1, row2);
190  tmp4 = _mm_unpackhi_epi32(row3, row4);
191 
192  row1 = _mm_unpacklo_epi64(tmp1, tmp2);
193  row2 = _mm_unpackhi_epi64(tmp1, tmp2);
194  row3 = _mm_unpacklo_epi64(tmp3, tmp4);
195  row4 = _mm_unpackhi_epi64(tmp3, tmp4);
196 
197  // store the transposed 4x4 submatrix back to the matrix
198  _mm_storeu_si128(reinterpret_cast<__m128i *>(&matrix[i][j]), row1);
199  _mm_storeu_si128(reinterpret_cast<__m128i *>(&matrix[i + 1][j]),
200  row2);
201  _mm_storeu_si128(reinterpret_cast<__m128i *>(&matrix[i + 2][j]),
202  row3);
203  _mm_storeu_si128(reinterpret_cast<__m128i *>(&matrix[i + 3][j]),
204  row4);
205  }
206  }
207 }
208 
209 #endif
210 
211 #endif
void std_mtx_add(const T *A, const T *B, T *C, int rows, int cols)
Perform matrix addition on two matrices as flat arrays.
Definition: mtx.hpp:510
void mtx_mult(std::vector< double > A, std::vector< double > B, std::vector< double > C)
list C
Definition: linalg.py:24
list A
Definition: linalg.py:22
list B
Definition: linalg.py:23