diff options
Diffstat (limited to 'lib/zstd/common/compiler.h')
| -rw-r--r-- | lib/zstd/common/compiler.h | 151 | 
1 files changed, 128 insertions, 23 deletions
| diff --git a/lib/zstd/common/compiler.h b/lib/zstd/common/compiler.h index c42d39faf9bd..dc9bd15e174e 100644 --- a/lib/zstd/common/compiler.h +++ b/lib/zstd/common/compiler.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */  /* - * Copyright (c) Yann Collet, Facebook, Inc. + * Copyright (c) Meta Platforms, Inc. and affiliates.   * All rights reserved.   *   * This source code is licensed under both the BSD-style license (found in the @@ -11,6 +12,8 @@  #ifndef ZSTD_COMPILER_H  #define ZSTD_COMPILER_H +#include <linux/types.h> +  #include "portability_macros.h"  /*-******************************************************* @@ -41,12 +44,15 @@  */  #define WIN_CDECL +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ +#define UNUSED_ATTR __attribute__((unused)) +  /*   * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant   * parameters. They must be inlined for the compiler to eliminate the constant   * branches.   */ -#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR  /*   * HINT_INLINE is used to help the compiler generate better code. It is *not*   * used for "templates", so it can be tweaked based on the compilers @@ -61,11 +67,21 @@  #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5  #  define HINT_INLINE static INLINE_KEYWORD  #else -#  define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR +#  define HINT_INLINE FORCE_INLINE_TEMPLATE  #endif -/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ -#define UNUSED_ATTR __attribute__((unused)) +/* "soft" inline : + * The compiler is free to select if it's a good idea to inline or not. + * The main objective is to silence compiler warnings + * when a defined function in included but not used. + * + * Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit. + * Updating the prefix is probably preferable, but requires a fairly large codemod, + * since this name is used everywhere. + */ +#ifndef MEM_STATIC  /* already defined in Linux Kernel mem.h */ +#define MEM_STATIC static __inline UNUSED_ATTR +#endif  /* force no inlining */  #define FORCE_NOINLINE static __attribute__((__noinline__)) @@ -86,23 +102,24 @@  #  define PREFETCH_L1(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)  #  define PREFETCH_L2(ptr)  __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)  #elif defined(__aarch64__) -#  define PREFETCH_L1(ptr)  __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) -#  define PREFETCH_L2(ptr)  __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) +#  define PREFETCH_L1(ptr)  do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0) +#  define PREFETCH_L2(ptr)  do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)  #else -#  define PREFETCH_L1(ptr) (void)(ptr)  /* disabled */ -#  define PREFETCH_L2(ptr) (void)(ptr)  /* disabled */ +#  define PREFETCH_L1(ptr) do { (void)(ptr); } while (0)  /* disabled */ +#  define PREFETCH_L2(ptr) do { (void)(ptr); } while (0)  /* disabled */  #endif  /* NO_PREFETCH */  #define CACHELINE_SIZE 64 -#define PREFETCH_AREA(p, s)  {            \ -    const char* const _ptr = (const char*)(p);  \ -    size_t const _size = (size_t)(s);     \ -    size_t _pos;                          \ -    for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) {  \ -        PREFETCH_L2(_ptr + _pos);         \ -    }                                     \ -} +#define PREFETCH_AREA(p, s)                              \ +    do {                                                 \ +        const char* const _ptr = (const char*)(p);       \ +        size_t const _size = (size_t)(s);                \ +        size_t _pos;                                     \ +        for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ +            PREFETCH_L2(_ptr + _pos);                    \ +        }                                                \ +    } while (0)  /* vectorization   * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, @@ -126,16 +143,13 @@  #define UNLIKELY(x) (__builtin_expect((x), 0))  #if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) -#  define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); } +#  define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0)  #else -#  define ZSTD_UNREACHABLE { assert(0); } +#  define ZSTD_UNREACHABLE do { assert(0); } while (0)  #endif  /* disable warnings */ -/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ - -  /* compile time determination of SIMD support */  /* C-language Attributes are added in C23. */ @@ -158,9 +172,15 @@  #define ZSTD_FALLTHROUGH fallthrough  /*-************************************************************** -*  Alignment check +*  Alignment  *****************************************************************/ +/* @return 1 if @u is a 2^n value, 0 otherwise + * useful to check a value is valid for alignment restrictions */ +MEM_STATIC int ZSTD_isPower2(size_t u) { +    return (u & (u-1)) == 0; +} +  /* this test was initially positioned in mem.h,   * but this file is removed (or replaced) for linux kernel   * so it's now hosted in compiler.h, @@ -175,10 +195,95 @@  #endif /* ZSTD_ALIGNOF */ +#ifndef ZSTD_ALIGNED +/* C90-compatible alignment macro (GCC/Clang). Adjust for other compilers if needed. */ +#define ZSTD_ALIGNED(a) __attribute__((aligned(a))) +#endif /* ZSTD_ALIGNED */ + +  /*-**************************************************************  *  Sanitizer  *****************************************************************/ +/* + * Zstd relies on pointer overflow in its decompressor. + * We add this attribute to functions that rely on pointer overflow. + */ +#ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +#  if __has_attribute(no_sanitize) +#    if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8 +       /* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */ +#      define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow"))) +#    else +       /* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */ +#      define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow"))) +#    endif +#  else +#    define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +#  endif +#endif + +/* + * Helper function to perform a wrapped pointer difference without triggering + * UBSAN. + * + * @returns lhs - rhs with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs) +{ +    return lhs - rhs; +} + +/* + * Helper function to perform a wrapped pointer add without triggering UBSAN. + * + * @return ptr + add with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add) +{ +    return ptr + add; +} + +/* + * Helper function to perform a wrapped pointer subtraction without triggering + * UBSAN. + * + * @return ptr - sub with wrapping + */ +MEM_STATIC +ZSTD_ALLOW_POINTER_OVERFLOW_ATTR +unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub) +{ +    return ptr - sub; +} + +/* + * Helper function to add to a pointer that works around C's undefined behavior + * of adding 0 to NULL. + * + * @returns `ptr + add` except it defines `NULL + 0 == NULL`. + */ +MEM_STATIC +unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add) +{ +    return add > 0 ? ptr + add : ptr; +} + +/* Issue #3240 reports an ASAN failure on an llvm-mingw build. Out of an + * abundance of caution, disable our custom poisoning on mingw. */ +#ifdef __MINGW32__ +#ifndef ZSTD_ASAN_DONT_POISON_WORKSPACE +#define ZSTD_ASAN_DONT_POISON_WORKSPACE 1 +#endif +#ifndef ZSTD_MSAN_DONT_POISON_WORKSPACE +#define ZSTD_MSAN_DONT_POISON_WORKSPACE 1 +#endif +#endif +  #endif /* ZSTD_COMPILER_H */ | 
