snappy-internal.h 16 KB

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