openGPMP
Open Source Mathematics Package
mtx_sse2_vec_f64.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 #elif defined(__SSE2__)
48 // SSE2
49 #include <emmintrin.h>
50 #include <smmintrin.h>
51 
52 /************************************************************************
53  *
54  * Matrix Operations on vector<vector>
55  *
56  ************************************************************************/
57 
58 void gpmp::linalg::Mtx::mtx_add(const std::vector<std::vector<double>> &A,
59  const std::vector<std::vector<double>> &B,
60  std::vector<std::vector<double>> &C) {
61  const int rows = A.size();
62  const int cols = A[0].size();
63 
64  for (int i = 0; i < rows; ++i) {
65  int j = 0;
66  // requires at least size 2x2 matrices for SSE2
67  for (; j < cols - 1; j += 2) {
68  // load 2 elements from A, B, and C matrices using SSE2
69  __m128d a = _mm_loadu_pd(&A[i][j]);
70  __m128d b = _mm_loadu_pd(&B[i][j]);
71  __m128d c = _mm_loadu_pd(&C[i][j]);
72 
73  // perform vectorized addition
74  c = _mm_add_pd(a, b);
75 
76  // store the result back to the C matrix
77  _mm_storeu_pd(&C[i][j], c);
78  }
79 
80  // handle the remaining elements that are not multiples of 2
81  for (; j < cols; ++j) {
82  C[i][j] = A[i][j] + B[i][j];
83  }
84  }
85 }
86 
87 // matrix subtraction using Intel intrinsics, accepts double types
88 void gpmp::linalg::Mtx::mtx_sub(const std::vector<std::vector<double>> &A,
89  const std::vector<std::vector<double>> &B,
90  std::vector<std::vector<double>> &C) {
91  const int rows = A.size();
92  const int cols = A[0].size();
93 
94  for (int i = 0; i < rows; ++i) {
95  int j = 0;
96  // requires at least size 2x2 matrices for SSE2
97  for (; j < cols - 1; j += 2) {
98  // load 2 elements from A, B, and C matrices using SSE2
99  __m128d a = _mm_loadu_pd(&A[i][j]);
100  __m128d b = _mm_loadu_pd(&B[i][j]);
101  __m128d c = _mm_loadu_pd(&C[i][j]);
102 
103  // perform vectorized subtraction
104  c = _mm_sub_pd(a, b);
105 
106  // store the result back to the C matrix
107  _mm_storeu_pd(&C[i][j], c);
108  }
109 
110  // handle the remaining elements that are not multiples of 2
111  for (; j < cols; ++j) {
112  C[i][j] = A[i][j] - B[i][j];
113  }
114  }
115 }
116 
117 // matrix multiplication using Intel intrinsics, accepts double types
118 void gpmp::linalg::Mtx::mtx_mult(const std::vector<std::vector<double>> &A,
119  const std::vector<std::vector<double>> &B,
120  std::vector<std::vector<double>> &C) {
121  const int rows_a = A.size();
122  const int cols_a = A[0].size();
123  const int cols_b = B[0].size();
124 
125  for (int i = 0; i < rows_a; ++i) {
126  for (int j = 0; j < cols_b; j += 2) {
127  // initialize a vector of zeros for the result
128  __m128d c = _mm_setzero_pd();
129 
130  for (int k = 0; k < cols_a; ++k) {
131  // load 2 elements from matrices A and B using SSE2
132  __m128d a = _mm_set1_pd(A[i][k]);
133  __m128d b = _mm_loadu_pd(&B[k][j]);
134 
135  // perform vectorized multiplication
136  __m128d prod = _mm_mul_pd(a, b);
137 
138  // perform vectorized addition
139  c = _mm_add_pd(c, prod);
140  }
141 
142  // store the result back to the C matrix
143  _mm_storeu_pd(&C[i][j], c);
144  }
145 
146  // handle the remaining elements that are not multiples of 2
147  for (int j = cols_b - cols_b % 2; j < cols_b; ++j) {
148  double sum = 0.0;
149 
150  for (int k = 0; k < cols_a; ++k) {
151  sum += A[i][k] * B[k][j];
152  }
153 
154  C[i][j] = sum;
155  }
156  }
157 }
158 
159 // transpose matrices of type double using Intel intrinsics
160 void gpmp::linalg::Mtx::mtx_tpose(std::vector<std::vector<double>> &matrix) {
161  const int rows = matrix.size();
162  const int cols = matrix[0].size();
163 
164  for (int i = 0; i < rows; i += 2) {
165  for (int j = i; j < cols; j += 2) {
166  __m128d row1 = _mm_loadu_pd(&matrix[i][j]);
167  __m128d row2 = _mm_loadu_pd(&matrix[i + 1][j]);
168 
169  // transpose 2x2 submatrix
170  __m128d tmp1 = _mm_unpacklo_pd(row1, row2);
171  __m128d tmp2 = _mm_unpackhi_pd(row1, row2);
172 
173  // store the transposed 2x2 submatrix back to the matrix
174  _mm_storeu_pd(&matrix[i][j], tmp1);
175  _mm_storeu_pd(&matrix[i + 1][j], tmp2);
176  }
177  }
178 }
179 
180 #endif
181 
182 #endif
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