/ algorithms / src / msm / variable_base / prefetch.rs
prefetch.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  #[macro_export]
 17  macro_rules! prefetch_slice {
 18      ($curve: ident, $slice_1: ident, $slice_2: ident, $prefetch_iter: ident) => {
 19          if let Some((idp_1, idp_2)) = $prefetch_iter.next() {
 20              $crate::msm::variable_base::prefetch::prefetch::<$curve>(&$slice_1[*idp_1 as usize]);
 21              $crate::msm::variable_base::prefetch::prefetch::<$curve>(&$slice_2[*idp_2 as usize]);
 22          }
 23      };
 24  
 25      ($curve: ident, $slice_1: ident, $prefetch_iter: ident) => {
 26          if let Some((idp_1, _)) = $prefetch_iter.next() {
 27              $crate::msm::variable_base::prefetch::prefetch::<$curve>(&$slice_1[*idp_1 as usize]);
 28          }
 29      };
 30  }
 31  
 32  #[macro_export]
 33  macro_rules! prefetch_slice_write {
 34      ($curve: ident, $slice_1: ident, $slice_2: ident, $prefetch_iter: ident) => {
 35          if let Some((idp_1, idp_2)) = $prefetch_iter.next() {
 36              $crate::msm::variable_base::prefetch::prefetch::<$curve>(&$slice_1[*idp_1 as usize]);
 37              if *idp_2 != !0u32 {
 38                  $crate::msm::variable_base::prefetch::prefetch::<$curve>(&$slice_2[*idp_2 as usize]);
 39              }
 40          }
 41      };
 42  }
 43  
 44  const fn n_lines<T>() -> isize {
 45      ((std::mem::size_of::<T>() - 1) / 64 + 1) as isize
 46  }
 47  
 48  #[macro_export]
 49  macro_rules! unroll {
 50      (0, |$i:ident| $s:stmt) => {};
 51      (1, |$i:ident| $s:stmt) => {{
 52          let $i: isize = 0;
 53          $s
 54      }};
 55      (2, |$i:ident| $s:stmt) => {{
 56          unroll!(1, |$i| $s);
 57          let $i: isize = 1;
 58          $s
 59      }};
 60      (3, |$i:ident| $s:stmt) => {{
 61          unroll!(2, |$i| $s);
 62          let $i: isize = 2;
 63          $s
 64      }};
 65      (4, |$i:ident| $s:stmt) => {{
 66          unroll!(3, |$i| $s);
 67          let $i: isize = 3;
 68          $s
 69      }};
 70      (5, |$i:ident| $s:stmt) => {{
 71          unroll!(4, |$i| $s);
 72          let $i: isize = 4;
 73          $s
 74      }};
 75      (6, |$i:ident| $s:stmt) => {{
 76          unroll!(5, |$i| $s);
 77          let $i: isize = 5;
 78          $s
 79      }};
 80      (7, |$i:ident| $s:stmt) => {{
 81          unroll!(6, |$i| $s);
 82          let $i: isize = 6;
 83          $s
 84      }};
 85      (8, |$i:ident| $s:stmt) => {{
 86          unroll!(7, |$i| $s);
 87          let $i: isize = 7;
 88          $s
 89      }};
 90      (9, |$i:ident| $s:stmt) => {{
 91          unroll!(8, |$i| $s);
 92          let $i: isize = 8;
 93          $s
 94      }};
 95      (10, |$i:ident| $s:stmt) => {{
 96          unroll!(9, |$i| $s);
 97          let $i: isize = 9;
 98          $s
 99      }};
100      (11, |$i:ident| $s:stmt) => {{
101          unroll!(10, |$i| $s);
102          let $i: isize = 10;
103          $s
104      }};
105      (12, |$i:ident| $s:stmt) => {{
106          unroll!(11, |$i| $s);
107          let $i: isize = 11;
108          $s
109      }};
110      (13, |$i:ident| $s:stmt) => {{
111          unroll!(12, |$i| $s);
112          let $i: isize = 12;
113          $s
114      }};
115      (14, |$i:ident| $s:stmt) => {{
116          unroll!(13, |$i| $s);
117          let $i: isize = 13;
118          $s
119      }};
120      (15, |$i:ident| $s:stmt) => {{
121          unroll!(14, |$i| $s);
122          let $i: isize = 14;
123          $s
124      }};
125      (16, |$i:ident| $s:stmt) => {{
126          unroll!(15, |$i| $s);
127          let $i: isize = 15;
128          $s
129      }};
130  }
131  
132  /// Prefetches as many cache lines as is occupied by the type T.
133  /// We assume 64B cache lines.
134  #[allow(unsafe_code)]
135  #[inline(always)]
136  pub fn prefetch<T>(p: *const T) {
137      unsafe {
138          match n_lines::<T>() {
139              1 => unroll!(1, |i| core::arch::x86_64::_mm_prefetch(
140                  (p as *const i8).offset(i * 64),
141                  core::arch::x86_64::_MM_HINT_T0
142              )),
143              2 => unroll!(2, |i| core::arch::x86_64::_mm_prefetch(
144                  (p as *const i8).offset(i * 64),
145                  core::arch::x86_64::_MM_HINT_T0
146              )),
147              3 => unroll!(3, |i| core::arch::x86_64::_mm_prefetch(
148                  (p as *const i8).offset(i * 64),
149                  core::arch::x86_64::_MM_HINT_T0
150              )),
151              4 => unroll!(4, |i| core::arch::x86_64::_mm_prefetch(
152                  (p as *const i8).offset(i * 64),
153                  core::arch::x86_64::_MM_HINT_T0
154              )),
155              5 => unroll!(5, |i| core::arch::x86_64::_mm_prefetch(
156                  (p as *const i8).offset(i * 64),
157                  core::arch::x86_64::_MM_HINT_T0
158              )),
159              6 => unroll!(6, |i| core::arch::x86_64::_mm_prefetch(
160                  (p as *const i8).offset(i * 64),
161                  core::arch::x86_64::_MM_HINT_T0
162              )),
163              7 => unroll!(7, |i| core::arch::x86_64::_mm_prefetch(
164                  (p as *const i8).offset(i * 64),
165                  core::arch::x86_64::_MM_HINT_T0
166              )),
167              8 => unroll!(8, |i| core::arch::x86_64::_mm_prefetch(
168                  (p as *const i8).offset(i * 64),
169                  core::arch::x86_64::_MM_HINT_T0
170              )),
171              9 => unroll!(9, |i| core::arch::x86_64::_mm_prefetch(
172                  (p as *const i8).offset(i * 64),
173                  core::arch::x86_64::_MM_HINT_T0
174              )),
175              10 => unroll!(10, |i| core::arch::x86_64::_mm_prefetch(
176                  (p as *const i8).offset(i * 64),
177                  core::arch::x86_64::_MM_HINT_T0
178              )),
179              11 => unroll!(11, |i| core::arch::x86_64::_mm_prefetch(
180                  (p as *const i8).offset(i * 64),
181                  core::arch::x86_64::_MM_HINT_T0
182              )),
183              12 => unroll!(12, |i| core::arch::x86_64::_mm_prefetch(
184                  (p as *const i8).offset(i * 64),
185                  core::arch::x86_64::_MM_HINT_T0
186              )),
187              13 => unroll!(13, |i| core::arch::x86_64::_mm_prefetch(
188                  (p as *const i8).offset(i * 64),
189                  core::arch::x86_64::_MM_HINT_T0
190              )),
191              14 => unroll!(14, |i| core::arch::x86_64::_mm_prefetch(
192                  (p as *const i8).offset(i * 64),
193                  core::arch::x86_64::_MM_HINT_T0
194              )),
195              15 => unroll!(15, |i| core::arch::x86_64::_mm_prefetch(
196                  (p as *const i8).offset(i * 64),
197                  core::arch::x86_64::_MM_HINT_T0
198              )),
199              _ => unroll!(16, |i| core::arch::x86_64::_mm_prefetch(
200                  (p as *const i8).offset(i * 64),
201                  core::arch::x86_64::_MM_HINT_T0
202              )),
203          }
204      }
205  }