1/* Copyright 2013 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 endianness, branch prediction and unaligned loads and stores. */
8
9#ifndef BROTLI_ENC_PORT_H_
10#define BROTLI_ENC_PORT_H_
11
12#include <assert.h>
13#include <string.h>  /* memcpy */
14
15#include <brotli/port.h>
16#include <brotli/types.h>
17
18#if defined OS_LINUX || defined OS_CYGWIN
19#include <endian.h>
20#elif defined OS_FREEBSD
21#include <machine/endian.h>
22#elif defined OS_MACOSX
23#include <machine/endian.h>
24/* Let's try and follow the Linux convention */
25#define __BYTE_ORDER  BYTE_ORDER
26#define __LITTLE_ENDIAN LITTLE_ENDIAN
27#endif
28
29/* define the macro IS_LITTLE_ENDIAN
30   using the above endian definitions from endian.h if
31   endian.h was included */
32#ifdef __BYTE_ORDER
33#if __BYTE_ORDER == __LITTLE_ENDIAN
34#define IS_LITTLE_ENDIAN
35#endif
36
37#else
38
39#if defined(__LITTLE_ENDIAN__)
40#define IS_LITTLE_ENDIAN
41#endif
42#endif  /* __BYTE_ORDER */
43
44#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
45#define IS_LITTLE_ENDIAN
46#endif
47
48/* Enable little-endian optimization for x64 architecture on Windows. */
49#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_X64)
50#define IS_LITTLE_ENDIAN
51#endif
52
53/* Portable handling of unaligned loads, stores, and copies.
54   On some platforms, like ARM, the copy functions can be more efficient
55   then a load and a store. */
56
57#if defined(ARCH_PIII) || \
58  defined(ARCH_ATHLON) || defined(ARCH_K8) || defined(_ARCH_PPC)
59
60/* x86 and x86-64 can perform unaligned loads/stores directly;
61   modern PowerPC hardware can also do unaligned integer loads and stores;
62   but note: the FPU still sends unaligned loads and stores to a trap handler!
63*/
64
65#define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p))
66#define BROTLI_UNALIGNED_LOAD64(_p) (*(const uint64_t *)(_p))
67
68#define BROTLI_UNALIGNED_STORE32(_p, _val) \
69  (*(uint32_t *)(_p) = (_val))
70#define BROTLI_UNALIGNED_STORE64(_p, _val) \
71  (*(uint64_t *)(_p) = (_val))
72
73#elif defined(__arm__) && \
74  !defined(__ARM_ARCH_5__) && \
75  !defined(__ARM_ARCH_5T__) && \
76  !defined(__ARM_ARCH_5TE__) && \
77  !defined(__ARM_ARCH_5TEJ__) && \
78  !defined(__ARM_ARCH_6__) && \
79  !defined(__ARM_ARCH_6J__) && \
80  !defined(__ARM_ARCH_6K__) && \
81  !defined(__ARM_ARCH_6Z__) && \
82  !defined(__ARM_ARCH_6ZK__) && \
83  !defined(__ARM_ARCH_6T2__)
84
85/* ARMv7 and newer support native unaligned accesses, but only of 16-bit
86   and 32-bit values (not 64-bit); older versions either raise a fatal signal,
87   do an unaligned read and rotate the words around a bit, or do the reads very
88   slowly (trip through kernel mode). */
89
90#define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p))
91#define BROTLI_UNALIGNED_STORE32(_p, _val) \
92  (*(uint32_t *)(_p) = (_val))
93
94static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64(const void *p) {
95  uint64_t t;
96  memcpy(&t, p, sizeof t);
97  return t;
98}
99
100static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64(void *p, uint64_t v) {
101  memcpy(p, &v, sizeof v);
102}
103
104#else
105
106/* These functions are provided for architectures that don't support */
107/* unaligned loads and stores. */
108
109static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32(const void *p) {
110  uint32_t t;
111  memcpy(&t, p, sizeof t);
112  return t;
113}
114
115static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64(const void *p) {
116  uint64_t t;
117  memcpy(&t, p, sizeof t);
118  return t;
119}
120
121static BROTLI_INLINE void BROTLI_UNALIGNED_STORE32(void *p, uint32_t v) {
122  memcpy(p, &v, sizeof v);
123}
124
125static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64(void *p, uint64_t v) {
126  memcpy(p, &v, sizeof v);
127}
128
129#endif
130
131#define TEMPLATE_(T)                                                           \
132  static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \
133  static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; }
134TEMPLATE_(double) TEMPLATE_(float) TEMPLATE_(int)
135TEMPLATE_(size_t) TEMPLATE_(uint32_t) TEMPLATE_(uint8_t)
136#undef TEMPLATE_
137#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
138#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
139
140#define BROTLI_SWAP(T, A, I, J) { \
141  T __brotli_swap_tmp = (A)[(I)]; \
142  (A)[(I)] = (A)[(J)];            \
143  (A)[(J)] = __brotli_swap_tmp;   \
144}
145
146#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) {  \
147  if (C < (R)) {                                 \
148    size_t _new_size = (C == 0) ? (R) : C;       \
149    T* new_array;                                \
150    while (_new_size < (R)) _new_size *= 2;      \
151    new_array = BROTLI_ALLOC((M), T, _new_size); \
152    if (!BROTLI_IS_OOM(m) && C != 0)             \
153      memcpy(new_array, A, C * sizeof(T));       \
154    BROTLI_FREE((M), A);                         \
155    A = new_array;                               \
156    C = _new_size;                               \
157  }                                              \
158}
159
160#endif  /* BROTLI_ENC_PORT_H_ */
161