snarkvm_algorithms/msm/variable_base/
prefetch.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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]
17macro_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]
33macro_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
44const fn n_lines<T>() -> isize {
45    ((std::mem::size_of::<T>() - 1) / 64 + 1) as isize
46}
47
48#[macro_export]
49macro_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)]
136pub 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}