snappy-internal.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright 2008 Google Inc. All Rights Reserved.
  2. //
  3. // Redistribution and use in source and binary forms, with or without
  4. // modification, are permitted provided that the following conditions are
  5. // met:
  6. //
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above
  10. // copyright notice, this list of conditions and the following disclaimer
  11. // in the documentation and/or other materials provided with the
  12. // distribution.
  13. // * Neither the name of Google Inc. nor the names of its
  14. // contributors may be used to endorse or promote products derived from
  15. // this software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Internals shared between the Snappy implementation and its unittest.
  30. #ifndef THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_
  31. #define THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_
  32. #include "snappy-stubs-internal.h"
  33. #if SNAPPY_HAVE_SSSE3
  34. // Please do not replace with <x86intrin.h> or with headers that assume more
  35. // advanced SSE versions without checking with all the OWNERS.
  36. #include <emmintrin.h>
  37. #include <tmmintrin.h>
  38. #endif
  39. #if SNAPPY_HAVE_NEON
  40. #include <arm_neon.h>
  41. #endif
  42. #if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON
  43. #define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1
  44. #else
  45. #define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 0
  46. #endif
  47. namespace snappy {
  48. namespace internal {
  49. #if SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  50. #if SNAPPY_HAVE_SSSE3
  51. using V128 = __m128i;
  52. #elif SNAPPY_HAVE_NEON
  53. using V128 = uint8x16_t;
  54. #endif
  55. // Load 128 bits of integer data. `src` must be 16-byte aligned.
  56. inline V128 V128_Load(const V128* src);
  57. // Load 128 bits of integer data. `src` does not need to be aligned.
  58. inline V128 V128_LoadU(const V128* src);
  59. // Store 128 bits of integer data. `dst` does not need to be aligned.
  60. inline void V128_StoreU(V128* dst, V128 val);
  61. // Shuffle packed 8-bit integers using a shuffle mask.
  62. // Each packed integer in the shuffle mask must be in [0,16).
  63. inline V128 V128_Shuffle(V128 input, V128 shuffle_mask);
  64. // Constructs V128 with 16 chars |c|.
  65. inline V128 V128_DupChar(char c);
  66. #if SNAPPY_HAVE_SSSE3
  67. inline V128 V128_Load(const V128* src) { return _mm_load_si128(src); }
  68. inline V128 V128_LoadU(const V128* src) { return _mm_loadu_si128(src); }
  69. inline void V128_StoreU(V128* dst, V128 val) { _mm_storeu_si128(dst, val); }
  70. inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
  71. return _mm_shuffle_epi8(input, shuffle_mask);
  72. }
  73. inline V128 V128_DupChar(char c) { return _mm_set1_epi8(c); }
  74. #elif SNAPPY_HAVE_NEON
  75. inline V128 V128_Load(const V128* src) {
  76. return vld1q_u8(reinterpret_cast<const uint8_t*>(src));
  77. }
  78. inline V128 V128_LoadU(const V128* src) {
  79. return vld1q_u8(reinterpret_cast<const uint8_t*>(src));
  80. }
  81. inline void V128_StoreU(V128* dst, V128 val) {
  82. vst1q_u8(reinterpret_cast<uint8_t*>(dst), val);
  83. }
  84. inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
  85. assert(vminvq_u8(shuffle_mask) >= 0 && vmaxvq_u8(shuffle_mask) <= 15);
  86. return vqtbl1q_u8(input, shuffle_mask);
  87. }
  88. inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); }
  89. #endif
  90. #endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  91. // Working memory performs a single allocation to hold all scratch space
  92. // required for compression.
  93. class WorkingMemory {
  94. public:
  95. explicit WorkingMemory(size_t input_size);
  96. ~WorkingMemory();
  97. // Allocates and clears a hash table using memory in "*this",
  98. // stores the number of buckets in "*table_size" and returns a pointer to
  99. // the base of the hash table.
  100. uint16_t* GetHashTable(size_t fragment_size, int* table_size) const;
  101. char* GetScratchInput() const { return input_; }
  102. char* GetScratchOutput() const { return output_; }
  103. private:
  104. char* mem_; // the allocated memory, never nullptr
  105. size_t size_; // the size of the allocated memory, never 0
  106. uint16_t* table_; // the pointer to the hashtable
  107. char* input_; // the pointer to the input scratch buffer
  108. char* output_; // the pointer to the output scratch buffer
  109. // No copying
  110. WorkingMemory(const WorkingMemory&);
  111. void operator=(const WorkingMemory&);
  112. };
  113. // Flat array compression that does not emit the "uncompressed length"
  114. // prefix. Compresses "input" string to the "*op" buffer.
  115. //
  116. // REQUIRES: "input_length <= kBlockSize"
  117. // REQUIRES: "op" points to an array of memory that is at least
  118. // "MaxCompressedLength(input_length)" in size.
  119. // REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
  120. // REQUIRES: "table_size" is a power of two
  121. //
  122. // Returns an "end" pointer into "op" buffer.
  123. // "end - op" is the compressed size of "input".
  124. char* CompressFragment(const char* input,
  125. size_t input_length,
  126. char* op,
  127. uint16_t* table,
  128. const int table_size);
  129. // Find the largest n such that
  130. //
  131. // s1[0,n-1] == s2[0,n-1]
  132. // and n <= (s2_limit - s2).
  133. //
  134. // Return make_pair(n, n < 8).
  135. // Does not read *s2_limit or beyond.
  136. // Does not read *(s1 + (s2_limit - s2)) or beyond.
  137. // Requires that s2_limit >= s2.
  138. //
  139. // In addition populate *data with the next 5 bytes from the end of the match.
  140. // This is only done if 8 bytes are available (s2_limit - s2 >= 8). The point is
  141. // that on some arch's this can be done faster in this routine than subsequent
  142. // loading from s2 + n.
  143. //
  144. // Separate implementation for 64-bit, little-endian cpus.
  145. #if !SNAPPY_IS_BIG_ENDIAN && \
  146. (defined(__x86_64__) || defined(_M_X64) || defined(ARCH_PPC) || \
  147. defined(ARCH_ARM))
  148. static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
  149. const char* s2,
  150. const char* s2_limit,
  151. uint64_t* data) {
  152. assert(s2_limit >= s2);
  153. size_t matched = 0;
  154. // This block isn't necessary for correctness; we could just start looping
  155. // immediately. As an optimization though, it is useful. It creates some not
  156. // uncommon code paths that determine, without extra effort, whether the match
  157. // length is less than 8. In short, we are hoping to avoid a conditional
  158. // branch, and perhaps get better code layout from the C++ compiler.
  159. if (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 16)) {
  160. uint64_t a1 = UNALIGNED_LOAD64(s1);
  161. uint64_t a2 = UNALIGNED_LOAD64(s2);
  162. if (SNAPPY_PREDICT_TRUE(a1 != a2)) {
  163. // This code is critical for performance. The reason is that it determines
  164. // how much to advance `ip` (s2). This obviously depends on both the loads
  165. // from the `candidate` (s1) and `ip`. Furthermore the next `candidate`
  166. // depends on the advanced `ip` calculated here through a load, hash and
  167. // new candidate hash lookup (a lot of cycles). This makes s1 (ie.
  168. // `candidate`) the variable that limits throughput. This is the reason we
  169. // go through hoops to have this function update `data` for the next iter.
  170. // The straightforward code would use *data, given by
  171. //
  172. // *data = UNALIGNED_LOAD64(s2 + matched_bytes) (Latency of 5 cycles),
  173. //
  174. // as input for the hash table lookup to find next candidate. However
  175. // this forces the load on the data dependency chain of s1, because
  176. // matched_bytes directly depends on s1. However matched_bytes is 0..7, so
  177. // we can also calculate *data by
  178. //
  179. // *data = AlignRight(UNALIGNED_LOAD64(s2), UNALIGNED_LOAD64(s2 + 8),
  180. // matched_bytes);
  181. //
  182. // The loads do not depend on s1 anymore and are thus off the bottleneck.
  183. // The straightforward implementation on x86_64 would be to use
  184. //
  185. // shrd rax, rdx, cl (cl being matched_bytes * 8)
  186. //
  187. // unfortunately shrd with a variable shift has a 4 cycle latency. So this
  188. // only wins 1 cycle. The BMI2 shrx instruction is a 1 cycle variable
  189. // shift instruction but can only shift 64 bits. If we focus on just
  190. // obtaining the least significant 4 bytes, we can obtain this by
  191. //
  192. // *data = ConditionalMove(matched_bytes < 4, UNALIGNED_LOAD64(s2),
  193. // UNALIGNED_LOAD64(s2 + 4) >> ((matched_bytes & 3) * 8);
  194. //
  195. // Writen like above this is not a big win, the conditional move would be
  196. // a cmp followed by a cmov (2 cycles) followed by a shift (1 cycle).
  197. // However matched_bytes < 4 is equal to
  198. // static_cast<uint32_t>(xorval) != 0. Writen that way, the conditional
  199. // move (2 cycles) can execute in parallel with FindLSBSetNonZero64
  200. // (tzcnt), which takes 3 cycles.
  201. uint64_t xorval = a1 ^ a2;
  202. int shift = Bits::FindLSBSetNonZero64(xorval);
  203. size_t matched_bytes = shift >> 3;
  204. uint64_t a3 = UNALIGNED_LOAD64(s2 + 4);
  205. #ifndef __x86_64__
  206. a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
  207. #else
  208. // Ideally this would just be
  209. //
  210. // a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
  211. //
  212. // However clang correctly infers that the above statement participates on
  213. // a critical data dependency chain and thus, unfortunately, refuses to
  214. // use a conditional move (it's tuned to cut data dependencies). In this
  215. // case there is a longer parallel chain anyway AND this will be fairly
  216. // unpredictable.
  217. asm("testl %k2, %k2\n\t"
  218. "cmovzq %1, %0\n\t"
  219. : "+r"(a2)
  220. : "r"(a3), "r"(xorval)
  221. : "cc");
  222. #endif
  223. *data = a2 >> (shift & (3 * 8));
  224. return std::pair<size_t, bool>(matched_bytes, true);
  225. } else {
  226. matched = 8;
  227. s2 += 8;
  228. }
  229. }
  230. // Find out how long the match is. We loop over the data 64 bits at a
  231. // time until we find a 64-bit block that doesn't match; then we find
  232. // the first non-matching bit and use that to calculate the total
  233. // length of the match.
  234. while (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 16)) {
  235. uint64_t a1 = UNALIGNED_LOAD64(s1 + matched);
  236. uint64_t a2 = UNALIGNED_LOAD64(s2);
  237. if (a1 == a2) {
  238. s2 += 8;
  239. matched += 8;
  240. } else {
  241. uint64_t xorval = a1 ^ a2;
  242. int shift = Bits::FindLSBSetNonZero64(xorval);
  243. size_t matched_bytes = shift >> 3;
  244. uint64_t a3 = UNALIGNED_LOAD64(s2 + 4);
  245. #ifndef __x86_64__
  246. a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
  247. #else
  248. asm("testl %k2, %k2\n\t"
  249. "cmovzq %1, %0\n\t"
  250. : "+r"(a2)
  251. : "r"(a3), "r"(xorval)
  252. : "cc");
  253. #endif
  254. *data = a2 >> (shift & (3 * 8));
  255. matched += matched_bytes;
  256. assert(matched >= 8);
  257. return std::pair<size_t, bool>(matched, false);
  258. }
  259. }
  260. while (SNAPPY_PREDICT_TRUE(s2 < s2_limit)) {
  261. if (s1[matched] == *s2) {
  262. ++s2;
  263. ++matched;
  264. } else {
  265. if (s2 <= s2_limit - 8) {
  266. *data = UNALIGNED_LOAD64(s2);
  267. }
  268. return std::pair<size_t, bool>(matched, matched < 8);
  269. }
  270. }
  271. return std::pair<size_t, bool>(matched, matched < 8);
  272. }
  273. #else
  274. static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
  275. const char* s2,
  276. const char* s2_limit,
  277. uint64_t* data) {
  278. // Implementation based on the x86-64 version, above.
  279. assert(s2_limit >= s2);
  280. int matched = 0;
  281. while (s2 <= s2_limit - 4 &&
  282. UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) {
  283. s2 += 4;
  284. matched += 4;
  285. }
  286. if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) {
  287. uint32_t x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched);
  288. int matching_bits = Bits::FindLSBSetNonZero(x);
  289. matched += matching_bits >> 3;
  290. s2 += matching_bits >> 3;
  291. } else {
  292. while ((s2 < s2_limit) && (s1[matched] == *s2)) {
  293. ++s2;
  294. ++matched;
  295. }
  296. }
  297. if (s2 <= s2_limit - 8) *data = LittleEndian::Load64(s2);
  298. return std::pair<size_t, bool>(matched, matched < 8);
  299. }
  300. #endif
  301. // Lookup tables for decompression code. Give --snappy_dump_decompression_table
  302. // to the unit test to recompute char_table.
  303. enum {
  304. LITERAL = 0,
  305. COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode
  306. COPY_2_BYTE_OFFSET = 2,
  307. COPY_4_BYTE_OFFSET = 3
  308. };
  309. static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset.
  310. // Data stored per entry in lookup table:
  311. // Range Bits-used Description
  312. // ------------------------------------
  313. // 1..64 0..7 Literal/copy length encoded in opcode byte
  314. // 0..7 8..10 Copy offset encoded in opcode byte / 256
  315. // 0..4 11..13 Extra bytes after opcode
  316. //
  317. // We use eight bits for the length even though 7 would have sufficed
  318. // because of efficiency reasons:
  319. // (1) Extracting a byte is faster than a bit-field
  320. // (2) It properly aligns copy offset so we do not need a <<8
  321. static constexpr uint16_t char_table[256] = {
  322. // clang-format off
  323. 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002,
  324. 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004,
  325. 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006,
  326. 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008,
  327. 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a,
  328. 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c,
  329. 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e,
  330. 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010,
  331. 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012,
  332. 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014,
  333. 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016,
  334. 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018,
  335. 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a,
  336. 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c,
  337. 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e,
  338. 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020,
  339. 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022,
  340. 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024,
  341. 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026,
  342. 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028,
  343. 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a,
  344. 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c,
  345. 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e,
  346. 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030,
  347. 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032,
  348. 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034,
  349. 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036,
  350. 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038,
  351. 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a,
  352. 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c,
  353. 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e,
  354. 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040,
  355. // clang-format on
  356. };
  357. } // end namespace internal
  358. } // end namespace snappy
  359. #endif // THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_