port.h revision e7e3849835e17ebb842ad02b51e1fb0c5e11b47c
1/* Copyright 2015 Google Inc. All Rights Reserved.
2
3   Distributed under MIT license.
4   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*/
6
7/* Macros for compiler / platform specific features and build options.
8
9   Build options are:
10    * BROTLI_BUILD_32_BIT disables 64-bit optimizations
11    * BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
12    * BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
13    * BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
14    * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
15    * BROTLI_BUILD_MODERN_COMPILER forces to use modern compilers built-ins,
16      features and attributes
17    * BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
18      read and overlapping memcpy; this reduces decompression speed by 5%
19    * BROTLI_DEBUG dumps file name and line number when decoder detects stream
20      or memory error
21    * BROTLI_ENABLE_LOG enables asserts and dumps various state information
22 */
23
24#ifndef BROTLI_DEC_PORT_H_
25#define BROTLI_DEC_PORT_H_
26
27#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
28#include <assert.h>
29#include <stdio.h>
30#endif
31
32/* Compatibility with non-clang compilers. */
33#ifndef __has_builtin
34#define __has_builtin(x) 0
35#endif
36
37#ifndef __has_attribute
38#define __has_attribute(x) 0
39#endif
40
41#ifndef __has_feature
42#define __has_feature(x) 0
43#endif
44
45#if defined(__arm__) || defined(__thumb__) || \
46    defined(_M_ARM) || defined(_M_ARMT)
47#define BROTLI_TARGET_ARM
48#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) || \
49    (defined(M_ARM) && (M_ARM >= 7))
50#define BROTLI_TARGET_ARMV7
51#endif  /* ARMv7 */
52#if defined(__aarch64__)
53#define BROTLI_TARGET_ARMV8
54#endif  /* ARMv8 */
55#endif  /* ARM */
56
57#if defined(__i386) || defined(_M_IX86)
58#define BROTLI_TARGET_X86
59#endif
60
61#if defined(__x86_64__) || defined(_M_X64)
62#define BROTLI_TARGET_X64
63#endif
64
65#if defined(__PPC64__)
66#define BROTLI_TARGET_POWERPC64
67#endif
68
69#if defined(__GNUC__) && defined(__GNUC_MINOR__)
70#define BROTLI_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
71#else
72#define BROTLI_GCC_VERSION 0
73#endif
74
75#if defined(__ICC)
76#define BROTLI_ICC_VERSION __ICC
77#else
78#define BROTLI_ICC_VERSION 0
79#endif
80
81#if defined(BROTLI_BUILD_MODERN_COMPILER)
82#define BROTLI_MODERN_COMPILER 1
83#elif (BROTLI_GCC_VERSION > 300) || (BROTLI_ICC_VERSION >= 1600)
84#define BROTLI_MODERN_COMPILER 1
85#else
86#define BROTLI_MODERN_COMPILER 0
87#endif
88
89#ifdef BROTLI_BUILD_PORTABLE
90#define BROTLI_ALIGNED_READ (!!1)
91#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
92     defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8)
93/* Allow unaligned read only for whitelisted CPUs. */
94#define BROTLI_ALIGNED_READ (!!0)
95#else
96#define BROTLI_ALIGNED_READ (!!1)
97#endif
98
99/* Define "PREDICT_TRUE" and "PREDICT_FALSE" macros for capable compilers.
100
101To apply compiler hint, enclose the branching condition into macros, like this:
102
103  if (PREDICT_TRUE(zero == 0)) {
104    // main execution path
105  } else {
106    // compiler should place this code outside of main execution path
107  }
108
109OR:
110
111  if (PREDICT_FALSE(something_rare_or_unexpected_happens)) {
112    // compiler should place this code outside of main execution path
113  }
114
115*/
116#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_expect)
117#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
118#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
119#else
120#define PREDICT_FALSE(x) (x)
121#define PREDICT_TRUE(x) (x)
122#endif
123
124/* IS_CONSTANT macros returns true for compile-time constant expressions. */
125#if BROTLI_MODERN_COMPILER || __has_builtin(__builtin_constant_p)
126#define IS_CONSTANT(x) (!!__builtin_constant_p(x))
127#else
128#define IS_CONSTANT(x) (!!0)
129#endif
130
131#if BROTLI_MODERN_COMPILER || __has_attribute(always_inline)
132#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
133#else
134#define ATTRIBUTE_ALWAYS_INLINE
135#endif
136
137#if BROTLI_MODERN_COMPILER || __has_attribute(visibility)
138#define ATTRIBUTE_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden")))
139#else
140#define ATTRIBUTE_VISIBILITY_HIDDEN
141#endif
142
143#ifndef BROTLI_INTERNAL
144#define BROTLI_INTERNAL ATTRIBUTE_VISIBILITY_HIDDEN
145#endif
146
147#ifndef _MSC_VER
148#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
149    __STDC_VERSION__ >= 199901L
150#define BROTLI_INLINE inline ATTRIBUTE_ALWAYS_INLINE
151#else
152#define BROTLI_INLINE
153#endif
154#else  /* _MSC_VER */
155#define BROTLI_INLINE __forceinline
156#endif  /* _MSC_VER */
157
158#ifdef BROTLI_ENABLE_LOG
159#define BROTLI_DCHECK(x) assert(x)
160#define BROTLI_LOG(x) printf x
161#else
162#define BROTLI_DCHECK(x)
163#define BROTLI_LOG(x)
164#endif
165
166#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
167static inline void BrotliDump(const char* f, int l, const char* fn) {
168  fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
169  fflush(stderr);
170}
171#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
172#else
173#define BROTLI_DUMP() (void)(0)
174#endif
175
176#if defined(BROTLI_BUILD_64_BIT)
177#define BROTLI_64_BITS 1
178#elif defined(BROTLI_BUILD_32_BIT)
179#define BROTLI_64_BITS 0
180#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8) || \
181    defined(BROTLI_TARGET_POWERPC64)
182#define BROTLI_64_BITS 1
183#else
184#define BROTLI_64_BITS 0
185#endif
186
187#if defined(BROTLI_BUILD_BIG_ENDIAN)
188#define BROTLI_LITTLE_ENDIAN 0
189#define BROTLI_BIG_ENDIAN 1
190#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
191#define BROTLI_LITTLE_ENDIAN 1
192#define BROTLI_BIG_ENDIAN 0
193#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
194#define BROTLI_LITTLE_ENDIAN 0
195#define BROTLI_BIG_ENDIAN 0
196#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
197#define BROTLI_LITTLE_ENDIAN 1
198#define BROTLI_BIG_ENDIAN 0
199#elif defined(_WIN32)
200/* Win32 can currently always be assumed to be little endian */
201#define BROTLI_LITTLE_ENDIAN 1
202#define BROTLI_BIG_ENDIAN 0
203#else
204#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
205#define BROTLI_BIG_ENDIAN 1
206#else
207#define BROTLI_BIG_ENDIAN 0
208#endif
209#define BROTLI_LITTLE_ENDIAN 0
210#endif
211
212#if BROTLI_MODERN_COMPILER || __has_attribute(noinline)
213#define BROTLI_NOINLINE __attribute__((noinline))
214#else
215#define BROTLI_NOINLINE
216#endif
217
218#define BROTLI_REPEAT(N, X) {     \
219  if ((N & 1) != 0) {X;}          \
220  if ((N & 2) != 0) {X; X;}       \
221  if ((N & 4) != 0) {X; X; X; X;} \
222}
223
224#if BROTLI_MODERN_COMPILER || defined(__llvm__)
225#if defined(BROTLI_TARGET_ARMV7)
226static BROTLI_INLINE unsigned BrotliRBit(unsigned input) {
227  unsigned output;
228  __asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
229  return output;
230}
231#define BROTLI_RBIT(x) BrotliRBit(x)
232#endif  /* armv7 */
233#endif  /* gcc || clang */
234
235#if defined(BROTLI_TARGET_ARM)
236#define BROTLI_HAS_UBFX (!!1)
237#else
238#define BROTLI_HAS_UBFX (!!0)
239#endif
240
241#define BROTLI_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
242
243#define BROTLI_FREE(S, X) {                  \
244  S->free_func(S->memory_manager_opaque, X); \
245  X = NULL;                                  \
246}
247
248#define BROTLI_UNUSED(X) (void)(X)
249
250#endif  /* BROTLI_DEC_PORT_H_ */
251