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 BROTLI_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 BROTLI_LITTLE_ENDIAN 35 #endif 36 37 #else 38 39 #if defined(__LITTLE_ENDIAN__) 40 #define BROTLI_LITTLE_ENDIAN 41 #endif 42 #endif /* __BYTE_ORDER */ 43 44 #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 45 #define BROTLI_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 BROTLI_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(BROTLI_LITTLE_ENDIAN) && (\ 58 defined(ARCH_PIII) || defined(ARCH_ATHLON) || \ 59 defined(ARCH_K8) || defined(_ARCH_PPC)) 60 61 /* x86 and x86-64 can perform unaligned loads/stores directly; 62 modern PowerPC hardware can also do unaligned integer loads and stores; 63 but note: the FPU still sends unaligned loads and stores to a trap handler! 64 */ 65 66 #define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p)) 67 #define BROTLI_UNALIGNED_LOAD64LE(_p) (*(const uint64_t *)(_p)) 68 69 #define BROTLI_UNALIGNED_STORE64LE(_p, _val) \ 70 (*(uint64_t *)(_p) = (_val)) 71 72 #elif defined(BROTLI_LITTLE_ENDIAN) && defined(__arm__) && \ 73 !defined(__ARM_ARCH_5__) && \ 74 !defined(__ARM_ARCH_5T__) && \ 75 !defined(__ARM_ARCH_5TE__) && \ 76 !defined(__ARM_ARCH_5TEJ__) && \ 77 !defined(__ARM_ARCH_6__) && \ 78 !defined(__ARM_ARCH_6J__) && \ 79 !defined(__ARM_ARCH_6K__) && \ 80 !defined(__ARM_ARCH_6Z__) && \ 81 !defined(__ARM_ARCH_6ZK__) && \ 82 !defined(__ARM_ARCH_6T2__) 83 84 /* ARMv7 and newer support native unaligned accesses, but only of 16-bit 85 and 32-bit values (not 64-bit); older versions either raise a fatal signal, 86 do an unaligned read and rotate the words around a bit, or do the reads very 87 slowly (trip through kernel mode). */ 88 89 #define BROTLI_UNALIGNED_LOAD32(_p) (*(const uint32_t *)(_p)) 90 91 static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) { 92 uint64_t t; 93 memcpy(&t, p, sizeof t); 94 return t; 95 } 96 97 static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) { 98 memcpy(p, &v, sizeof v); 99 } 100 101 #else 102 103 /* These functions are provided for architectures that don't support */ 104 /* unaligned loads and stores. */ 105 106 static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32(const void *p) { 107 uint32_t t; 108 memcpy(&t, p, sizeof t); 109 return t; 110 } 111 112 #if defined(BROTLI_LITTLE_ENDIAN) 113 114 static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) { 115 uint64_t t; 116 memcpy(&t, p, sizeof t); 117 return t; 118 } 119 120 static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) { 121 memcpy(p, &v, sizeof v); 122 } 123 124 #else /* BROTLI_LITTLE_ENDIAN */ 125 126 static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void *p) { 127 const uint8_t* in = (const uint8_t*)p; 128 uint64_t value = (uint64_t)(in[0]); 129 value |= (uint64_t)(in[1]) << 8; 130 value |= (uint64_t)(in[2]) << 16; 131 value |= (uint64_t)(in[3]) << 24; 132 value |= (uint64_t)(in[4]) << 32; 133 value |= (uint64_t)(in[5]) << 40; 134 value |= (uint64_t)(in[6]) << 48; 135 value |= (uint64_t)(in[7]) << 56; 136 return value; 137 } 138 139 static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void *p, uint64_t v) { 140 uint8_t* out = (uint8_t*)p; 141 out[0] = (uint8_t)v; 142 out[1] = (uint8_t)(v >> 8); 143 out[2] = (uint8_t)(v >> 16); 144 out[3] = (uint8_t)(v >> 24); 145 out[4] = (uint8_t)(v >> 32); 146 out[5] = (uint8_t)(v >> 40); 147 out[6] = (uint8_t)(v >> 48); 148 out[7] = (uint8_t)(v >> 56); 149 } 150 151 #endif /* BROTLI_LITTLE_ENDIAN */ 152 153 #endif 154 155 #define TEMPLATE_(T) \ 156 static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \ 157 static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; } 158 TEMPLATE_(double) TEMPLATE_(float) TEMPLATE_(int) 159 TEMPLATE_(size_t) TEMPLATE_(uint32_t) TEMPLATE_(uint8_t) 160 #undef TEMPLATE_ 161 #define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B))) 162 #define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B))) 163 164 #define BROTLI_SWAP(T, A, I, J) { \ 165 T __brotli_swap_tmp = (A)[(I)]; \ 166 (A)[(I)] = (A)[(J)]; \ 167 (A)[(J)] = __brotli_swap_tmp; \ 168 } 169 170 #define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \ 171 if (C < (R)) { \ 172 size_t _new_size = (C == 0) ? (R) : C; \ 173 T* new_array; \ 174 while (_new_size < (R)) _new_size *= 2; \ 175 new_array = BROTLI_ALLOC((M), T, _new_size); \ 176 if (!BROTLI_IS_OOM(m) && C != 0) \ 177 memcpy(new_array, A, C * sizeof(T)); \ 178 BROTLI_FREE((M), A); \ 179 A = new_array; \ 180 C = _new_size; \ 181 } \ 182 } 183 184 #endif /* BROTLI_ENC_PORT_H_ */ 185