1*65d1f550SNick Terrell /* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
2e0c1b49fSNick Terrell /*
3*65d1f550SNick Terrell * Copyright (c) Meta Platforms, Inc. and affiliates.
4e0c1b49fSNick Terrell * All rights reserved.
5e0c1b49fSNick Terrell *
6e0c1b49fSNick Terrell * This source code is licensed under both the BSD-style license (found in the
7e0c1b49fSNick Terrell * LICENSE file in the root directory of this source tree) and the GPLv2 (found
8e0c1b49fSNick Terrell * in the COPYING file in the root directory of this source tree).
9e0c1b49fSNick Terrell * You may select, at your option, one of the above-listed licenses.
10e0c1b49fSNick Terrell */
11e0c1b49fSNick Terrell
12e0c1b49fSNick Terrell #ifndef ZSTD_COMPILER_H
13e0c1b49fSNick Terrell #define ZSTD_COMPILER_H
14e0c1b49fSNick Terrell
15*65d1f550SNick Terrell #include <linux/types.h>
16*65d1f550SNick Terrell
172aa14b1aSNick Terrell #include "portability_macros.h"
182aa14b1aSNick Terrell
19e0c1b49fSNick Terrell /*-*******************************************************
20e0c1b49fSNick Terrell * Compiler specifics
21e0c1b49fSNick Terrell *********************************************************/
22e0c1b49fSNick Terrell /* force inlining */
23e0c1b49fSNick Terrell
241974990cSNick Terrell #if !defined(ZSTD_NO_INLINE)
25e0c1b49fSNick Terrell #if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
26e0c1b49fSNick Terrell # define INLINE_KEYWORD inline
27e0c1b49fSNick Terrell #else
28e0c1b49fSNick Terrell # define INLINE_KEYWORD
29e0c1b49fSNick Terrell #endif
30e0c1b49fSNick Terrell
31e0c1b49fSNick Terrell #define FORCE_INLINE_ATTR __attribute__((always_inline))
32e0c1b49fSNick Terrell
331974990cSNick Terrell #else
341974990cSNick Terrell
351974990cSNick Terrell #define INLINE_KEYWORD
361974990cSNick Terrell #define FORCE_INLINE_ATTR
371974990cSNick Terrell
381974990cSNick Terrell #endif
39e0c1b49fSNick Terrell
40e0c1b49fSNick Terrell /*
41e0c1b49fSNick Terrell On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC).
422aa14b1aSNick Terrell This explicitly marks such functions as __cdecl so that the code will still compile
43e0c1b49fSNick Terrell if a CC other than __cdecl has been made the default.
44e0c1b49fSNick Terrell */
45e0c1b49fSNick Terrell #define WIN_CDECL
46e0c1b49fSNick Terrell
47*65d1f550SNick Terrell /* UNUSED_ATTR tells the compiler it is okay if the function is unused. */
48*65d1f550SNick Terrell #define UNUSED_ATTR __attribute__((unused))
49*65d1f550SNick Terrell
50e0c1b49fSNick Terrell /*
51e0c1b49fSNick Terrell * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant
52e0c1b49fSNick Terrell * parameters. They must be inlined for the compiler to eliminate the constant
53e0c1b49fSNick Terrell * branches.
54e0c1b49fSNick Terrell */
55*65d1f550SNick Terrell #define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR
56e0c1b49fSNick Terrell /*
57e0c1b49fSNick Terrell * HINT_INLINE is used to help the compiler generate better code. It is *not*
58e0c1b49fSNick Terrell * used for "templates", so it can be tweaked based on the compilers
59e0c1b49fSNick Terrell * performance.
60e0c1b49fSNick Terrell *
61e0c1b49fSNick Terrell * gcc-4.8 and gcc-4.9 have been shown to benefit from leaving off the
62e0c1b49fSNick Terrell * always_inline attribute.
63e0c1b49fSNick Terrell *
64e0c1b49fSNick Terrell * clang up to 5.0.0 (trunk) benefit tremendously from the always_inline
65e0c1b49fSNick Terrell * attribute.
66e0c1b49fSNick Terrell */
67e0c1b49fSNick Terrell #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5
68e0c1b49fSNick Terrell # define HINT_INLINE static INLINE_KEYWORD
69e0c1b49fSNick Terrell #else
70*65d1f550SNick Terrell # define HINT_INLINE FORCE_INLINE_TEMPLATE
71e0c1b49fSNick Terrell #endif
72e0c1b49fSNick Terrell
73*65d1f550SNick Terrell /* "soft" inline :
74*65d1f550SNick Terrell * The compiler is free to select if it's a good idea to inline or not.
75*65d1f550SNick Terrell * The main objective is to silence compiler warnings
76*65d1f550SNick Terrell * when a defined function in included but not used.
77*65d1f550SNick Terrell *
78*65d1f550SNick Terrell * Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit.
79*65d1f550SNick Terrell * Updating the prefix is probably preferable, but requires a fairly large codemod,
80*65d1f550SNick Terrell * since this name is used everywhere.
81*65d1f550SNick Terrell */
82*65d1f550SNick Terrell #ifndef MEM_STATIC /* already defined in Linux Kernel mem.h */
83*65d1f550SNick Terrell #define MEM_STATIC static __inline UNUSED_ATTR
84*65d1f550SNick Terrell #endif
85e0c1b49fSNick Terrell
86e0c1b49fSNick Terrell /* force no inlining */
87e0c1b49fSNick Terrell #define FORCE_NOINLINE static __attribute__((__noinline__))
88e0c1b49fSNick Terrell
89e0c1b49fSNick Terrell
90e0c1b49fSNick Terrell /* target attribute */
91e0c1b49fSNick Terrell #define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
92e0c1b49fSNick Terrell
932aa14b1aSNick Terrell /* Target attribute for BMI2 dynamic dispatch.
942aa14b1aSNick Terrell * Enable lzcnt, bmi, and bmi2.
952aa14b1aSNick Terrell * We test for bmi1 & bmi2. lzcnt is included in bmi1.
96e0c1b49fSNick Terrell */
972aa14b1aSNick Terrell #define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2")
98e0c1b49fSNick Terrell
99e0c1b49fSNick Terrell /* prefetch
100e0c1b49fSNick Terrell * can be disabled, by declaring NO_PREFETCH build macro */
101e0c1b49fSNick Terrell #if ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
102e0c1b49fSNick Terrell # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
103e0c1b49fSNick Terrell # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
104e0c1b49fSNick Terrell #elif defined(__aarch64__)
105*65d1f550SNick Terrell # define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0)
106*65d1f550SNick Terrell # define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)
107e0c1b49fSNick Terrell #else
108*65d1f550SNick Terrell # define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
109*65d1f550SNick Terrell # define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
110e0c1b49fSNick Terrell #endif /* NO_PREFETCH */
111e0c1b49fSNick Terrell
112e0c1b49fSNick Terrell #define CACHELINE_SIZE 64
113e0c1b49fSNick Terrell
114*65d1f550SNick Terrell #define PREFETCH_AREA(p, s) \
115*65d1f550SNick Terrell do { \
116e0c1b49fSNick Terrell const char* const _ptr = (const char*)(p); \
117e0c1b49fSNick Terrell size_t const _size = (size_t)(s); \
118e0c1b49fSNick Terrell size_t _pos; \
119e0c1b49fSNick Terrell for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
120e0c1b49fSNick Terrell PREFETCH_L2(_ptr + _pos); \
121e0c1b49fSNick Terrell } \
122*65d1f550SNick Terrell } while (0)
123e0c1b49fSNick Terrell
124e0c1b49fSNick Terrell /* vectorization
1252aa14b1aSNick Terrell * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
1262aa14b1aSNick Terrell * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */
1272aa14b1aSNick Terrell #if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__)
128e0c1b49fSNick Terrell # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5)
129e0c1b49fSNick Terrell # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
130e0c1b49fSNick Terrell # else
131e0c1b49fSNick Terrell # define DONT_VECTORIZE _Pragma("GCC optimize(\"no-tree-vectorize\")")
132e0c1b49fSNick Terrell # endif
133e0c1b49fSNick Terrell #else
134e0c1b49fSNick Terrell # define DONT_VECTORIZE
135e0c1b49fSNick Terrell #endif
136e0c1b49fSNick Terrell
137e0c1b49fSNick Terrell /* Tell the compiler that a branch is likely or unlikely.
138e0c1b49fSNick Terrell * Only use these macros if it causes the compiler to generate better code.
139e0c1b49fSNick Terrell * If you can remove a LIKELY/UNLIKELY annotation without speed changes in gcc
140e0c1b49fSNick Terrell * and clang, please do.
141e0c1b49fSNick Terrell */
142e0c1b49fSNick Terrell #define LIKELY(x) (__builtin_expect((x), 1))
143e0c1b49fSNick Terrell #define UNLIKELY(x) (__builtin_expect((x), 0))
144e0c1b49fSNick Terrell
1452aa14b1aSNick Terrell #if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
146*65d1f550SNick Terrell # define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0)
1472aa14b1aSNick Terrell #else
148*65d1f550SNick Terrell # define ZSTD_UNREACHABLE do { assert(0); } while (0)
1492aa14b1aSNick Terrell #endif
1502aa14b1aSNick Terrell
151e0c1b49fSNick Terrell /* disable warnings */
152e0c1b49fSNick Terrell
1532aa14b1aSNick Terrell /* compile time determination of SIMD support */
154e0c1b49fSNick Terrell
155e0c1b49fSNick Terrell /* C-language Attributes are added in C23. */
156e0c1b49fSNick Terrell #if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute)
157e0c1b49fSNick Terrell # define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
158e0c1b49fSNick Terrell #else
159e0c1b49fSNick Terrell # define ZSTD_HAS_C_ATTRIBUTE(x) 0
160e0c1b49fSNick Terrell #endif
161e0c1b49fSNick Terrell
162e0c1b49fSNick Terrell /* Only use C++ attributes in C++. Some compilers report support for C++
163e0c1b49fSNick Terrell * attributes when compiling with C.
164e0c1b49fSNick Terrell */
165e0c1b49fSNick Terrell #define ZSTD_HAS_CPP_ATTRIBUTE(x) 0
166e0c1b49fSNick Terrell
167e0c1b49fSNick Terrell /* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute.
168e0c1b49fSNick Terrell * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough
169e0c1b49fSNick Terrell * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough
170e0c1b49fSNick Terrell * - Else: __attribute__((__fallthrough__))
171e0c1b49fSNick Terrell */
172e0c1b49fSNick Terrell #define ZSTD_FALLTHROUGH fallthrough
173e0c1b49fSNick Terrell
1742aa14b1aSNick Terrell /*-**************************************************************
175*65d1f550SNick Terrell * Alignment
1762aa14b1aSNick Terrell *****************************************************************/
177e0c1b49fSNick Terrell
178*65d1f550SNick Terrell /* @return 1 if @u is a 2^n value, 0 otherwise
179*65d1f550SNick Terrell * useful to check a value is valid for alignment restrictions */
ZSTD_isPower2(size_t u)180*65d1f550SNick Terrell MEM_STATIC int ZSTD_isPower2(size_t u) {
181*65d1f550SNick Terrell return (u & (u-1)) == 0;
182*65d1f550SNick Terrell }
183*65d1f550SNick Terrell
1842aa14b1aSNick Terrell /* this test was initially positioned in mem.h,
1852aa14b1aSNick Terrell * but this file is removed (or replaced) for linux kernel
1862aa14b1aSNick Terrell * so it's now hosted in compiler.h,
1872aa14b1aSNick Terrell * which remains valid for both user & kernel spaces.
1882aa14b1aSNick Terrell */
189e0c1b49fSNick Terrell
1902aa14b1aSNick Terrell #ifndef ZSTD_ALIGNOF
1912aa14b1aSNick Terrell /* covers gcc, clang & MSVC */
1922aa14b1aSNick Terrell /* note : this section must come first, before C11,
1932aa14b1aSNick Terrell * due to a limitation in the kernel source generator */
1942aa14b1aSNick Terrell # define ZSTD_ALIGNOF(T) __alignof(T)
1952aa14b1aSNick Terrell
1962aa14b1aSNick Terrell #endif /* ZSTD_ALIGNOF */
1972aa14b1aSNick Terrell
198*65d1f550SNick Terrell #ifndef ZSTD_ALIGNED
199*65d1f550SNick Terrell /* C90-compatible alignment macro (GCC/Clang). Adjust for other compilers if needed. */
200*65d1f550SNick Terrell #define ZSTD_ALIGNED(a) __attribute__((aligned(a)))
201*65d1f550SNick Terrell #endif /* ZSTD_ALIGNED */
202*65d1f550SNick Terrell
203*65d1f550SNick Terrell
2042aa14b1aSNick Terrell /*-**************************************************************
2052aa14b1aSNick Terrell * Sanitizer
2062aa14b1aSNick Terrell *****************************************************************/
2072aa14b1aSNick Terrell
208*65d1f550SNick Terrell /*
209*65d1f550SNick Terrell * Zstd relies on pointer overflow in its decompressor.
210*65d1f550SNick Terrell * We add this attribute to functions that rely on pointer overflow.
211*65d1f550SNick Terrell */
212*65d1f550SNick Terrell #ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
213*65d1f550SNick Terrell # if __has_attribute(no_sanitize)
214*65d1f550SNick Terrell # if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8
215*65d1f550SNick Terrell /* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */
216*65d1f550SNick Terrell # define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow")))
217*65d1f550SNick Terrell # else
218*65d1f550SNick Terrell /* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */
219*65d1f550SNick Terrell # define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow")))
220*65d1f550SNick Terrell # endif
221*65d1f550SNick Terrell # else
222*65d1f550SNick Terrell # define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
223*65d1f550SNick Terrell # endif
224*65d1f550SNick Terrell #endif
225*65d1f550SNick Terrell
226*65d1f550SNick Terrell /*
227*65d1f550SNick Terrell * Helper function to perform a wrapped pointer difference without triggering
228*65d1f550SNick Terrell * UBSAN.
229*65d1f550SNick Terrell *
230*65d1f550SNick Terrell * @returns lhs - rhs with wrapping
231*65d1f550SNick Terrell */
232*65d1f550SNick Terrell MEM_STATIC
233*65d1f550SNick Terrell ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
ZSTD_wrappedPtrDiff(unsigned char const * lhs,unsigned char const * rhs)234*65d1f550SNick Terrell ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs)
235*65d1f550SNick Terrell {
236*65d1f550SNick Terrell return lhs - rhs;
237*65d1f550SNick Terrell }
238*65d1f550SNick Terrell
239*65d1f550SNick Terrell /*
240*65d1f550SNick Terrell * Helper function to perform a wrapped pointer add without triggering UBSAN.
241*65d1f550SNick Terrell *
242*65d1f550SNick Terrell * @return ptr + add with wrapping
243*65d1f550SNick Terrell */
244*65d1f550SNick Terrell MEM_STATIC
245*65d1f550SNick Terrell ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
ZSTD_wrappedPtrAdd(unsigned char const * ptr,ptrdiff_t add)246*65d1f550SNick Terrell unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add)
247*65d1f550SNick Terrell {
248*65d1f550SNick Terrell return ptr + add;
249*65d1f550SNick Terrell }
250*65d1f550SNick Terrell
251*65d1f550SNick Terrell /*
252*65d1f550SNick Terrell * Helper function to perform a wrapped pointer subtraction without triggering
253*65d1f550SNick Terrell * UBSAN.
254*65d1f550SNick Terrell *
255*65d1f550SNick Terrell * @return ptr - sub with wrapping
256*65d1f550SNick Terrell */
257*65d1f550SNick Terrell MEM_STATIC
258*65d1f550SNick Terrell ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
ZSTD_wrappedPtrSub(unsigned char const * ptr,ptrdiff_t sub)259*65d1f550SNick Terrell unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub)
260*65d1f550SNick Terrell {
261*65d1f550SNick Terrell return ptr - sub;
262*65d1f550SNick Terrell }
263*65d1f550SNick Terrell
264*65d1f550SNick Terrell /*
265*65d1f550SNick Terrell * Helper function to add to a pointer that works around C's undefined behavior
266*65d1f550SNick Terrell * of adding 0 to NULL.
267*65d1f550SNick Terrell *
268*65d1f550SNick Terrell * @returns `ptr + add` except it defines `NULL + 0 == NULL`.
269*65d1f550SNick Terrell */
270*65d1f550SNick Terrell MEM_STATIC
ZSTD_maybeNullPtrAdd(unsigned char * ptr,ptrdiff_t add)271*65d1f550SNick Terrell unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add)
272*65d1f550SNick Terrell {
273*65d1f550SNick Terrell return add > 0 ? ptr + add : ptr;
274*65d1f550SNick Terrell }
275*65d1f550SNick Terrell
276*65d1f550SNick Terrell /* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an
277*65d1f550SNick Terrell * abundance of caution, disable our custom poisoning on mingw. */
278*65d1f550SNick Terrell #ifdef __MINGW32__
279*65d1f550SNick Terrell #ifndef ZSTD_ASAN_DONT_POISON_WORKSPACE
280*65d1f550SNick Terrell #define ZSTD_ASAN_DONT_POISON_WORKSPACE 1
281*65d1f550SNick Terrell #endif
282*65d1f550SNick Terrell #ifndef ZSTD_MSAN_DONT_POISON_WORKSPACE
283*65d1f550SNick Terrell #define ZSTD_MSAN_DONT_POISON_WORKSPACE 1
284*65d1f550SNick Terrell #endif
285*65d1f550SNick Terrell #endif
286*65d1f550SNick Terrell
287e0c1b49fSNick Terrell
288e0c1b49fSNick Terrell
289e0c1b49fSNick Terrell #endif /* ZSTD_COMPILER_H */
290