1 // Copyright 2022 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // TODO(b/265984188): remove all uses and delete this header.
16
17 #ifndef ABSL_BASE_INTERNAL_PREFETCH_H_
18 #define ABSL_BASE_INTERNAL_PREFETCH_H_
19
20 #include "absl/base/attributes.h"
21 #include "absl/base/config.h"
22 #include "absl/base/prefetch.h"
23
24 #ifdef __SSE__
25 #include <xmmintrin.h>
26 #endif
27
28 #if defined(_MSC_VER) && defined(ABSL_INTERNAL_HAVE_SSE)
29 #include <intrin.h>
30 #pragma intrinsic(_mm_prefetch)
31 #endif
32
33 // Compatibility wrappers around __builtin_prefetch, to prefetch data
34 // for read if supported by the toolchain.
35
36 // Move data into the cache before it is read, or "prefetch" it.
37 //
38 // The value of `addr` is the address of the memory to prefetch. If
39 // the target and compiler support it, data prefetch instructions are
40 // generated. If the prefetch is done some time before the memory is
41 // read, it may be in the cache by the time the read occurs.
42 //
43 // The function names specify the temporal locality heuristic applied,
44 // using the names of Intel prefetch instructions:
45 //
46 // T0 - high degree of temporal locality; data should be left in as
47 // many levels of the cache possible
48 // T1 - moderate degree of temporal locality
49 // T2 - low degree of temporal locality
50 // Nta - no temporal locality, data need not be left in the cache
51 // after the read
52 //
53 // Incorrect or gratuitous use of these functions can degrade
54 // performance, so use them only when representative benchmarks show
55 // an improvement.
56 //
57 // Example usage:
58 //
59 // absl::base_internal::PrefetchT0(addr);
60 //
61 // Currently, the different prefetch calls behave on some Intel
62 // architectures as follows:
63 //
64 // SNB..SKL SKX
65 // PrefetchT0() L1/L2/L3 L1/L2
66 // PrefetchT1() L2/L3 L2
67 // PrefetchT2() L2/L3 L2
68 // PrefetchNta() L1/--/L3 L1*
69 //
70 // * On SKX PrefetchNta() will bring the line into L1 but will evict
71 // from L3 cache. This might result in surprising behavior.
72 //
73 // SNB = Sandy Bridge, SKL = Skylake, SKX = Skylake Xeon.
74 //
75 namespace absl {
76 ABSL_NAMESPACE_BEGIN
77 namespace base_internal {
78
79 ABSL_DEPRECATED("Use absl::PrefetchToLocalCache() instead")
PrefetchT0(const void * address)80 inline void PrefetchT0(const void* address) {
81 absl::PrefetchToLocalCache(address);
82 }
83
84 ABSL_DEPRECATED("Use absl::PrefetchToLocalCache() instead")
PrefetchNta(const void * address)85 inline void PrefetchNta(const void* address) {
86 absl::PrefetchToLocalCacheNta(address);
87 }
88
89 ABSL_DEPRECATED("Use __builtin_prefetch() for advanced prefetch logic instead")
90 void PrefetchT1(const void* addr);
91
92 ABSL_DEPRECATED("Use __builtin_prefetch() for advanced prefetch logic instead")
93 void PrefetchT2(const void* addr);
94
95 // Implementation details follow.
96
97 #if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
98
99 #define ABSL_INTERNAL_HAVE_PREFETCH 1
100
101 // See __builtin_prefetch:
102 // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
103 //
104 // These functions speculatively load for read only. This is
105 // safe for all currently supported platforms. However, prefetch for
106 // store may have problems depending on the target platform.
107 //
PrefetchT1(const void * addr)108 inline void PrefetchT1(const void* addr) {
109 // Note: this uses prefetcht1 on Intel.
110 __builtin_prefetch(addr, 0, 2);
111 }
PrefetchT2(const void * addr)112 inline void PrefetchT2(const void* addr) {
113 // Note: this uses prefetcht2 on Intel.
114 __builtin_prefetch(addr, 0, 1);
115 }
116
117 #elif defined(ABSL_INTERNAL_HAVE_SSE)
118
119 #define ABSL_INTERNAL_HAVE_PREFETCH 1
120
PrefetchT1(const void * addr)121 inline void PrefetchT1(const void* addr) {
122 _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T1);
123 }
PrefetchT2(const void * addr)124 inline void PrefetchT2(const void* addr) {
125 _mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T2);
126 }
127
128 #else
PrefetchT1(const void *)129 inline void PrefetchT1(const void*) {}
PrefetchT2(const void *)130 inline void PrefetchT2(const void*) {}
131 #endif
132
133 } // namespace base_internal
134 ABSL_NAMESPACE_END
135 } // namespace absl
136
137 #endif // ABSL_BASE_INTERNAL_PREFETCH_H_
138