_ZN6snappy6SourceD2Ev:
   36|  1.13k|Source::~Source() = default;
_ZNK6snappy15ByteArraySource9AvailableEv:
   68|  1.13k|size_t ByteArraySource::Available() const { return left_; }
_ZN6snappy15ByteArraySource4PeekEPm:
   70|  3.64k|const char* ByteArraySource::Peek(size_t* len) {
   71|  3.64k|  *len = left_;
   72|  3.64k|  return ptr_;
   73|  3.64k|}
_ZN6snappy15ByteArraySource4SkipEm:
   75|  5.66k|void ByteArraySource::Skip(size_t n) {
   76|  5.66k|  left_ -= n;
   77|  5.66k|  ptr_ += n;
   78|  5.66k|}

_ZN6snappy15ByteArraySourceC2EPKcm:
  148|  1.13k|  ByteArraySource(const char* p, size_t n) : ptr_(p), left_(n) { }
_ZN6snappy6SourceC2Ev:
  113|  1.13k|  Source() { }

_ZN6snappy6Varint16Parse32WithLimitEPKcS2_Pj:
  459|  2.32k|                                            uint32_t* OUTPUT) {
  460|  2.32k|  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
  461|  2.32k|  const unsigned char* limit = reinterpret_cast<const unsigned char*>(l);
  462|  2.32k|  uint32_t b, result;
  463|  2.32k|  if (ptr >= limit) return NULL;
  ------------------
  |  Branch (463:7): [True: 0, False: 2.32k]
  ------------------
  464|  2.32k|  b = *(ptr++); result = b & 127;          if (b < 128) goto done;
  ------------------
  |  Branch (464:48): [True: 1.02k, False: 1.30k]
  ------------------
  465|  1.30k|  if (ptr >= limit) return NULL;
  ------------------
  |  Branch (465:7): [True: 9, False: 1.29k]
  ------------------
  466|  1.29k|  b = *(ptr++); result |= (b & 127) <<  7; if (b < 128) goto done;
  ------------------
  |  Branch (466:48): [True: 780, False: 517]
  ------------------
  467|    517|  if (ptr >= limit) return NULL;
  ------------------
  |  Branch (467:7): [True: 9, False: 508]
  ------------------
  468|    508|  b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done;
  ------------------
  |  Branch (468:48): [True: 329, False: 179]
  ------------------
  469|    179|  if (ptr >= limit) return NULL;
  ------------------
  |  Branch (469:7): [True: 12, False: 167]
  ------------------
  470|    167|  b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done;
  ------------------
  |  Branch (470:48): [True: 28, False: 139]
  ------------------
  471|    139|  if (ptr >= limit) return NULL;
  ------------------
  |  Branch (471:7): [True: 10, False: 129]
  ------------------
  472|    129|  b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done;
  ------------------
  |  Branch (472:48): [True: 119, False: 10]
  ------------------
  473|     10|  return NULL;       // Value is too long to be a varint32
  474|  2.27k| done:
  475|  2.27k|  *OUTPUT = result;
  476|  2.27k|  return reinterpret_cast<const char*>(ptr);
  477|    129|}
_ZN6snappy12LittleEndian6Load32EPKv:
  196|   221k|  static inline uint32_t Load32(const void *ptr) {
  197|       |    // Compiles to a single mov/str on recent clang and gcc.
  198|       |#if SNAPPY_IS_BIG_ENDIAN
  199|       |    const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);
  200|       |    return (static_cast<uint32_t>(buffer[0])) |
  201|       |            (static_cast<uint32_t>(buffer[1]) << 8) |
  202|       |            (static_cast<uint32_t>(buffer[2]) << 16) |
  203|       |            (static_cast<uint32_t>(buffer[3]) << 24);
  204|       |#else
  205|       |    // See Load16() for the rationale of using memcpy().
  206|   221k|    uint32_t value;
  207|   221k|    std::memcpy(&value, ptr, 4);
  208|   221k|    return value;
  209|   221k|#endif
  210|   221k|  }
_ZN6snappy28STLStringResizeUninitializedEPNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEm:
  511|  1.13k|inline void STLStringResizeUninitialized(std::string* s, size_t new_size) {
  512|  1.13k|  s->resize(new_size);
  513|  1.13k|}
_ZN6snappy15string_as_arrayEPNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  527|  1.13k|inline char* string_as_array(std::string* str) {
  528|  1.13k|  return str->empty() ? NULL : &*str->begin();
  ------------------
  |  Branch (528:10): [True: 46, False: 1.08k]
  ------------------
  529|  1.13k|}

_ZN6snappy21GetUncompressedLengthEPKcmPm:
  731|  2.32k|bool GetUncompressedLength(const char* start, size_t n, size_t* result) {
  732|  2.32k|  uint32_t v = 0;
  733|  2.32k|  const char* limit = start + n;
  734|  2.32k|  if (Varint::Parse32WithLimit(start, limit, &v) != NULL) {
  ------------------
  |  Branch (734:7): [True: 2.27k, False: 50]
  ------------------
  735|  2.27k|    *result = v;
  736|  2.27k|    return true;
  737|  2.27k|  } else {
  738|     50|    return false;
  739|     50|  }
  740|  2.32k|}
_ZN6snappy9MemCopy64EPcPKvm:
 1249|   211k|void MemCopy64(char* dst, const void* src, size_t size) {
 1250|       |  // Always copy this many bytes.  If that's below size then copy the full 64.
 1251|   211k|  constexpr int kShortMemCopy = 32;
 1252|   211k|  (void)kShortMemCopy;
 1253|   211k|  assert(size <= 64);
  ------------------
  |  Branch (1253:3): [True: 211k, False: 0]
  ------------------
 1254|   211k|  assert(std::less_equal<const void*>()(static_cast<const char*>(src) + size,
  ------------------
  |  Branch (1254:3): [True: 14.1k, False: 197k]
  |  Branch (1254:3): [True: 197k, False: 0]
  |  Branch (1254:3): [True: 211k, False: 0]
  ------------------
 1255|   211k|                                        dst) ||
 1256|   211k|         std::less_equal<const void*>()(dst + size, src));
 1257|       |
 1258|       |  // We know that src and dst are at least size bytes apart. However, because we
 1259|       |  // might copy more than size bytes the copy still might overlap past size.
 1260|       |  // E.g. if src and dst appear consecutively in memory (src + size >= dst).
 1261|       |  // TODO: Investigate wider copies on other platforms.
 1262|       |#if defined(__x86_64__) && defined(__AVX__)
 1263|       |  assert(kShortMemCopy <= 32);
 1264|       |  __m256i data = _mm256_lddqu_si256(static_cast<const __m256i *>(src));
 1265|       |  _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst), data);
 1266|       |  // Profiling shows that nearly all copies are short.
 1267|       |  if (SNAPPY_PREDICT_FALSE(size > kShortMemCopy)) {
 1268|       |    data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1);
 1269|       |    _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data);
 1270|       |  }
 1271|       |  // RVV acceleration available on RISC-V when compiled with -march=rv64gcv
 1272|       |#elif defined(__riscv) && SNAPPY_HAVE_RVV
 1273|       |  // Cast pointers to the type we will operate on.
 1274|       |  unsigned char* dst_ptr = reinterpret_cast<unsigned char*>(dst);
 1275|       |  const unsigned char* src_ptr = reinterpret_cast<const unsigned char*>(src);
 1276|       |  size_t remaining_bytes = size;
 1277|       |  // Loop as long as there are bytes remaining to be copied.
 1278|       |  while (remaining_bytes > 0) {
 1279|       |    // Set vector configuration: e8 (8-bit elements), m2 (LMUL=2).
 1280|       |    // Use e8m2 configuration to maximize throughput.
 1281|       |    size_t vl = VSETVL_E8M2(remaining_bytes);
 1282|       |    // Load data from the current source pointer.
 1283|       |    vuint8m2_t vec = VLE8_V_U8M2(src_ptr, vl);
 1284|       |    // Store data to the current destination pointer.
 1285|       |    VSE8_V_U8M2(dst_ptr, vec, vl);
 1286|       |    // Update pointers and the remaining count.
 1287|       |    src_ptr += vl;
 1288|       |    dst_ptr += vl;
 1289|       |    remaining_bytes -= vl;
 1290|       |  }
 1291|       |
 1292|       |#else
 1293|   211k|  std::memmove(dst, src, kShortMemCopy);
 1294|       |  // Profiling shows that nearly all copies are short.
 1295|   211k|  if (SNAPPY_PREDICT_FALSE(size > kShortMemCopy)) {
  ------------------
  |  |   94|   211k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 8.45k, False: 203k]
  |  |  ------------------
  ------------------
 1296|  8.45k|    std::memmove(dst + kShortMemCopy,
 1297|  8.45k|                 static_cast<const uint8_t*>(src) + kShortMemCopy,
 1298|  8.45k|                 64 - kShortMemCopy);
 1299|  8.45k|  }
 1300|   211k|#endif
 1301|   211k|}
_ZN6snappy13ClearDeferredEPPKvPmPh:
 1311|   207k|                   uint8_t* safe_source) {
 1312|   207k|  *deferred_src = safe_source;
 1313|   207k|  *deferred_length = 0;
 1314|   207k|}
_ZN6snappy12DeferMemCopyEPPKvPmS1_m:
 1317|  15.6k|                  const void* src, size_t length) {
 1318|  15.6k|  *deferred_src = src;
 1319|  15.6k|  *deferred_length = length;
 1320|  15.6k|}
_ZN6snappy18SnappyDecompressor9RefillTagEv:
 1788|  2.13k|bool SnappyDecompressor::RefillTag() {
 1789|  2.13k|  const char* ip = ip_;
 1790|  2.13k|  if (ip == ip_limit_) {
  ------------------
  |  Branch (1790:7): [True: 1.37k, False: 758]
  ------------------
 1791|       |    // Fetch a new fragment from the reader
 1792|  1.37k|    reader_->Skip(peeked_);  // All peeked bytes are used up
 1793|  1.37k|    size_t n;
 1794|  1.37k|    ip = reader_->Peek(&n);
 1795|  1.37k|    peeked_ = n;
 1796|  1.37k|    eof_ = (n == 0);
 1797|  1.37k|    if (eof_) return false;
  ------------------
  |  Branch (1797:9): [True: 309, False: 1.06k]
  ------------------
 1798|  1.06k|    ip_limit_ = ip + n;
 1799|  1.06k|  }
 1800|       |
 1801|       |  // Read the tag character
 1802|  2.13k|  assert(ip < ip_limit_);
  ------------------
  |  Branch (1802:3): [True: 1.82k, False: 0]
  ------------------
 1803|  1.82k|  const unsigned char c = *(reinterpret_cast<const unsigned char*>(ip));
 1804|       |  // At this point make sure that the data for the next tag is consecutive.
 1805|       |  // For copy 1 this means the next 2 bytes (tag and 1 byte offset)
 1806|       |  // For copy 2 the next 3 bytes (tag and 2 byte offset)
 1807|       |  // For copy 4 the next 5 bytes (tag and 4 byte offset)
 1808|       |  // For all small literals we only need 1 byte buf for literals 60...63 the
 1809|       |  // length is encoded in 1...4 extra bytes.
 1810|  1.82k|  const uint32_t needed = CalculateNeeded(c);
 1811|  1.82k|  assert(needed <= sizeof(scratch_));
  ------------------
  |  Branch (1811:3): [True: 1.82k, False: 0]
  ------------------
 1812|       |
 1813|       |  // Read more bytes from reader if needed
 1814|  1.82k|  uint64_t nbuf = ip_limit_ - ip;
 1815|  1.82k|  if (nbuf < needed) {
  ------------------
  |  Branch (1815:7): [True: 15, False: 1.81k]
  ------------------
 1816|       |    // Stitch together bytes from ip and reader to form the word
 1817|       |    // contents.  We store the needed bytes in "scratch_".  They
 1818|       |    // will be consumed immediately by the caller since we do not
 1819|       |    // read more than we need.
 1820|     15|    std::memmove(scratch_, ip, nbuf);
 1821|     15|    reader_->Skip(peeked_);  // All peeked bytes are used up
 1822|     15|    peeked_ = 0;
 1823|     15|    while (nbuf < needed) {
  ------------------
  |  Branch (1823:12): [True: 15, False: 0]
  ------------------
 1824|     15|      size_t length;
 1825|     15|      const char* src = reader_->Peek(&length);
 1826|     15|      if (length == 0) return false;
  ------------------
  |  Branch (1826:11): [True: 15, False: 0]
  ------------------
 1827|      0|      uint64_t to_add = std::min<uint64_t>(needed - nbuf, length);
 1828|      0|      std::memcpy(scratch_ + nbuf, src, to_add);
 1829|      0|      nbuf += to_add;
 1830|      0|      reader_->Skip(to_add);
 1831|      0|    }
 1832|     15|    assert(nbuf == needed);
  ------------------
  |  Branch (1832:5): [True: 0, False: 0]
  ------------------
 1833|      0|    ip_ = scratch_;
 1834|      0|    ip_limit_ = scratch_ + needed;
 1835|  1.81k|  } else if (nbuf < kMaximumTagLength) {
  ------------------
  |  Branch (1835:14): [True: 886, False: 926]
  ------------------
 1836|       |    // Have enough bytes, but move into scratch_ so that we do not
 1837|       |    // read past end of input
 1838|    886|    std::memmove(scratch_, ip, nbuf);
 1839|    886|    reader_->Skip(peeked_);  // All peeked bytes are used up
 1840|    886|    peeked_ = 0;
 1841|    886|    ip_ = scratch_;
 1842|    886|    ip_limit_ = scratch_ + nbuf;
 1843|    926|  } else {
 1844|       |    // Pass pointer to buffer returned by reader_.
 1845|    926|    ip_ = ip;
 1846|    926|  }
 1847|  1.81k|  return true;
 1848|  1.82k|}
_ZN6snappy13RawUncompressEPKcmPc:
 2375|  1.13k|                   char* uncompressed) {
 2376|  1.13k|  ByteArraySource reader(compressed, compressed_length);
 2377|  1.13k|  return RawUncompress(&reader, uncompressed);
 2378|  1.13k|}
_ZN6snappy13RawUncompressEPNS_6SourceEPc:
 2380|  1.13k|bool RawUncompress(Source* compressed, char* uncompressed) {
 2381|  1.13k|  SnappyArrayWriter output(uncompressed);
 2382|  1.13k|  return InternalUncompress(compressed, &output);
 2383|  1.13k|}
_ZN6snappy10UncompressEPKcmPNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
 2386|  1.13k|                std::string* uncompressed) {
 2387|  1.13k|  size_t ulength;
 2388|  1.13k|  if (!GetUncompressedLength(compressed, compressed_length, &ulength)) {
  ------------------
  |  Branch (2388:7): [True: 0, False: 1.13k]
  ------------------
 2389|      0|    return false;
 2390|      0|  }
 2391|       |  // On 32-bit builds: max_size() < kuint32max.  Check for that instead
 2392|       |  // of crashing (e.g., consider externally specified compressed data).
 2393|  1.13k|  if (ulength > uncompressed->max_size()) {
  ------------------
  |  Branch (2393:7): [True: 0, False: 1.13k]
  ------------------
 2394|      0|    return false;
 2395|      0|  }
 2396|  1.13k|  STLStringResizeUninitialized(uncompressed, ulength);
 2397|  1.13k|  return RawUncompress(compressed, compressed_length,
 2398|  1.13k|                       string_as_array(uncompressed));
 2399|  1.13k|}
snappy.cc:_ZN6snappy12_GLOBAL__N_116UnalignedCopy128EPKvPv:
  235|  1.92k|void UnalignedCopy128(const void* src, void* dst) {
  236|       |  // std::memcpy() gets vectorized when the appropriate compiler options are
  237|       |  // used. For example, x86 compilers targeting SSE2+ will optimize to an SSE2
  238|       |  // load and store.
  239|  1.92k|  char tmp[16];
  240|  1.92k|  std::memcpy(tmp, src, 16);
  241|  1.92k|  std::memcpy(dst, tmp, 16);
  242|  1.92k|}
_ZN6snappy15CalculateNeededEh:
 1768|  1.82k|constexpr uint32_t CalculateNeeded(uint8_t tag) {
 1769|  1.82k|  return ((tag & 3) == 0 && tag >= (60 * 4))
  ------------------
  |  Branch (1769:11): [True: 1.22k, False: 607]
  |  Branch (1769:29): [True: 177, False: 1.04k]
  ------------------
 1770|  1.82k|             ? (tag >> 2) - 58
 1771|  1.82k|             : (0x05030201 >> ((tag * 8) & 31)) & 0xFF;
 1772|  1.82k|}
_ZN6snappy18SnappyDecompressorC2EPNS_6SourceE:
 1600|  1.13k|      : reader_(reader), ip_(NULL), ip_limit_(NULL), peeked_(0), eof_(false) {}
_ZN6snappy18SnappyDecompressor22ReadUncompressedLengthEPj:
 1613|  1.13k|  bool ReadUncompressedLength(uint32_t* result) {
 1614|  1.13k|    assert(ip_ == NULL);  // Must not have read anything yet
  ------------------
  |  Branch (1614:5): [True: 1.13k, False: 0]
  ------------------
 1615|       |    // Length is encoded in 1..5 bytes
 1616|  1.13k|    *result = 0;
 1617|  1.13k|    uint32_t shift = 0;
 1618|  2.10k|    while (true) {
  ------------------
  |  Branch (1618:12): [True: 2.10k, Folded]
  ------------------
 1619|  2.10k|      if (shift >= 32) return false;
  ------------------
  |  Branch (1619:11): [True: 0, False: 2.10k]
  ------------------
 1620|  2.10k|      size_t n;
 1621|  2.10k|      const char* ip = reader_->Peek(&n);
 1622|  2.10k|      if (n == 0) return false;
  ------------------
  |  Branch (1622:11): [True: 0, False: 2.10k]
  ------------------
 1623|  2.10k|      const unsigned char c = *(reinterpret_cast<const unsigned char*>(ip));
 1624|  2.10k|      reader_->Skip(1);
 1625|  2.10k|      uint32_t val = c & 0x7f;
 1626|  2.10k|      if (LeftShiftOverflows(static_cast<uint8_t>(val), shift)) return false;
  ------------------
  |  Branch (1626:11): [True: 0, False: 2.10k]
  ------------------
 1627|  2.10k|      *result |= val << shift;
 1628|  2.10k|      if (c < 128) {
  ------------------
  |  Branch (1628:11): [True: 1.13k, False: 976]
  ------------------
 1629|  1.13k|        break;
 1630|  1.13k|      }
 1631|    976|      shift += 7;
 1632|    976|    }
 1633|  1.13k|    return true;
 1634|  1.13k|  }
snappy.cc:_ZN6snappyL18LeftShiftOverflowsEhj:
 1229|  2.10k|static inline bool LeftShiftOverflows(uint8_t value, uint32_t shift) {
 1230|  2.10k|  assert(shift < 32);
  ------------------
  |  Branch (1230:3): [True: 2.10k, False: 0]
  ------------------
 1231|  2.10k|  static const uint8_t masks[] = {
 1232|  2.10k|      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //
 1233|  2.10k|      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //
 1234|  2.10k|      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //
 1235|  2.10k|      0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
 1236|  2.10k|  return (value & masks[shift]) != 0;
 1237|  2.10k|}
_ZN6snappy18SnappyDecompressorD2Ev:
 1602|  1.13k|  ~SnappyDecompressor() {
 1603|       |    // Advance past any bytes we peeked at from the reader
 1604|  1.13k|    reader_->Skip(peeked_);
 1605|  1.13k|  }
_ZN6snappy17SnappyArrayWriterC2EPc:
 2303|  1.13k|      : base_(dst),
 2304|  1.13k|        op_(dst),
 2305|  1.13k|        op_limit_(dst),
 2306|  1.13k|        op_limit_min_slop_(dst) {}  // Safe default see invariant.
_ZN6snappy18SnappyDecompressor10ResetLimitEPKc:
 1593|  2.94k|  void ResetLimit(const char* ip) {
 1594|  2.94k|    ip_limit_min_maxtaglen_ =
 1595|  2.94k|        ip_limit_ - std::min<ptrdiff_t>(ip_limit_ - ip, kMaximumTagLength - 1);
 1596|  2.94k|  }
_ZN6snappy20DecompressBranchlessIPcEENSt3__14pairIPKhlEES5_S5_lT_l:
 1457|  11.6k|    ptrdiff_t op_limit_min_slop) {
 1458|       |  // If deferred_src is invalid point it here.
 1459|  11.6k|  uint8_t safe_source[64];
 1460|  11.6k|  const void* deferred_src;
 1461|  11.6k|  size_t deferred_length;
 1462|  11.6k|  ClearDeferred(&deferred_src, &deferred_length, safe_source);
 1463|       |
 1464|       |  // We unroll the inner loop twice so we need twice the spare room.
 1465|  11.6k|  op_limit_min_slop -= kSlopBytes;
 1466|  11.6k|  if (2 * (kSlopBytes + 1) < ip_limit - ip && op < op_limit_min_slop) {
  ------------------
  |  Branch (1466:7): [True: 3.54k, False: 8.14k]
  |  Branch (1466:47): [True: 1.85k, False: 1.69k]
  ------------------
 1467|  1.85k|    const uint8_t* const ip_limit_min_slop = ip_limit - 2 * kSlopBytes - 1;
 1468|  1.85k|    ip++;
 1469|       |    // ip points just past the tag and we are touching at maximum kSlopBytes
 1470|       |    // in an iteration.
 1471|  1.85k|    size_t tag = ip[-1];
 1472|       |#if defined(__clang__) && defined(__aarch64__)
 1473|       |    // Workaround for https://bugs.llvm.org/show_bug.cgi?id=51317
 1474|       |    // when loading 1 byte, clang for aarch64 doesn't realize that it(ldrb)
 1475|       |    // comes with free zero-extension, so clang generates another
 1476|       |    // 'and xn, xm, 0xff' before it use that as the offset. This 'and' is
 1477|       |    // redundant and can be removed by adding this dummy asm, which gives
 1478|       |    // clang a hint that we're doing the zero-extension at the load.
 1479|       |    asm("" ::"r"(tag));
 1480|       |#endif
 1481|   106k|    do {
 1482|       |      // The throughput is limited by instructions, unrolling the inner loop
 1483|       |      // twice reduces the amount of instructions checking limits and also
 1484|       |      // leads to reduced mov's.
 1485|       |
 1486|   106k|      SNAPPY_PREFETCH(ip + 128);
  ------------------
  |  |  109|   106k|#define SNAPPY_PREFETCH(ptr) __builtin_prefetch(ptr, 0, 3)
  ------------------
 1487|   317k|      for (int i = 0; i < 2; i++) {
  ------------------
  |  Branch (1487:23): [True: 212k, False: 105k]
  ------------------
 1488|   212k|        const uint8_t* old_ip = ip;
 1489|   212k|        assert(tag == ip[-1]);
  ------------------
  |  Branch (1489:9): [True: 212k, False: 0]
  ------------------
 1490|       |        // For literals tag_type = 0, hence we will always obtain 0 from
 1491|       |        // ExtractLowBytes. For literals offset will thus be kLiteralOffset.
 1492|   212k|        ptrdiff_t len_minus_offset = kLengthMinusOffset[tag];
 1493|   212k|        uint32_t next;
 1494|       |#if defined(__aarch64__)
 1495|       |        size_t tag_type = AdvanceToNextTagARMOptimized(&ip, &tag);
 1496|       |        // We never need more than 16 bits. Doing a Load16 allows the compiler
 1497|       |        // to elide the masking operation in ExtractOffset.
 1498|       |        next = LittleEndian::Load16(old_ip);
 1499|       |#elif defined(__riscv)
 1500|       |        size_t tag_type = AdvanceToNextTagRVOptimized(&ip, &tag);
 1501|       |        // We never need more than 16 bits. Doing a Load16 allows the compiler
 1502|       |        // to elide the masking operation in ExtractOffset.
 1503|       |        next = LittleEndian::Load16(old_ip);
 1504|       |#else
 1505|   212k|        size_t tag_type = AdvanceToNextTagX86Optimized(&ip, &tag);
 1506|   212k|        next = LittleEndian::Load32(old_ip);
 1507|   212k|#endif
 1508|   212k|        size_t len = len_minus_offset & 0xFF;
 1509|   212k|        ptrdiff_t extracted = ExtractOffset(next, tag_type);
 1510|   212k|        ptrdiff_t len_min_offset = len_minus_offset - extracted;
 1511|   212k|        if (SNAPPY_PREDICT_FALSE(len_minus_offset > extracted)) {
  ------------------
  |  |   94|   212k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 196k, False: 15.7k]
  |  |  ------------------
  ------------------
 1512|   196k|          if (SNAPPY_PREDICT_FALSE(len & 0x80)) {
  ------------------
  |  |   94|   196k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 1.49k, False: 195k]
  |  |  ------------------
  ------------------
 1513|       |            // Exceptional case (long literal or copy 4).
 1514|       |            // Actually doing the copy here is negatively impacting the main
 1515|       |            // loop due to compiler incorrectly allocating a register for
 1516|       |            // this fallback. Hence we just break.
 1517|  1.58k|          break_loop:
 1518|  1.58k|            ip = old_ip;
 1519|  1.58k|            goto exit;
 1520|  1.49k|          }
 1521|       |          // Only copy-1 or copy-2 tags can get here.
 1522|   196k|          assert(tag_type == 1 || tag_type == 2);
  ------------------
  |  Branch (1522:11): [True: 1.82k, False: 193k]
  |  Branch (1522:11): [True: 193k, False: 0]
  |  Branch (1522:11): [True: 195k, False: 0]
  ------------------
 1523|   195k|          std::ptrdiff_t delta = (op + deferred_length) + len_min_offset - len;
 1524|       |          // Guard against copies before the buffer start.
 1525|       |          // Execute any deferred MemCopy since we write to dst here.
 1526|   195k|          MemCopy64(op_base + op, deferred_src, deferred_length);
 1527|   195k|          op += deferred_length;
 1528|   195k|          ClearDeferred(&deferred_src, &deferred_length, safe_source);
 1529|   195k|          if (SNAPPY_PREDICT_FALSE(delta < 0 ||
  ------------------
  |  |   94|   390k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 33, False: 195k]
  |  |  |  Branch (94:51): [True: 11, False: 195k]
  |  |  |  Branch (94:51): [True: 22, False: 195k]
  |  |  ------------------
  ------------------
 1530|   195k|                                  !Copy64BytesWithPatternExtension(
 1531|   195k|                                      op_base + op, len - len_min_offset))) {
 1532|     33|            goto break_loop;
 1533|     33|          }
 1534|       |          // We aren't deferring this copy so add length right away.
 1535|   195k|          op += len;
 1536|   195k|          continue;
 1537|   195k|        }
 1538|  15.7k|        std::ptrdiff_t delta = (op + deferred_length) + len_min_offset - len;
 1539|  15.7k|        if (SNAPPY_PREDICT_FALSE(delta < 0)) {
  ------------------
  |  |   94|  15.7k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 1.97k, False: 13.7k]
  |  |  ------------------
  ------------------
 1540|       |          // Due to the spurious offset in literals have this will trigger
 1541|       |          // at the start of a block when op is still smaller than 256.
 1542|  1.97k|          if (tag_type != 0) goto break_loop;
  ------------------
  |  Branch (1542:15): [True: 54, False: 1.91k]
  ------------------
 1543|  1.91k|          MemCopy64(op_base + op, deferred_src, deferred_length);
 1544|  1.91k|          op += deferred_length;
 1545|  1.91k|          DeferMemCopy(&deferred_src, &deferred_length, old_ip, len);
 1546|  1.91k|          continue;
 1547|  1.97k|        }
 1548|       |
 1549|       |        // For copies we need to copy from op_base + delta, for literals
 1550|       |        // we need to copy from ip instead of from the stream.
 1551|  13.7k|        const void* from =
 1552|  13.7k|            tag_type ? reinterpret_cast<void*>(op_base + delta) : old_ip;
  ------------------
  |  Branch (1552:13): [True: 10.1k, False: 3.57k]
  ------------------
 1553|  13.7k|        MemCopy64(op_base + op, deferred_src, deferred_length);
 1554|  13.7k|        op += deferred_length;
 1555|  13.7k|        DeferMemCopy(&deferred_src, &deferred_length, from, len);
 1556|  13.7k|      }
 1557|   106k|    } while (ip < ip_limit_min_slop &&
  ------------------
  |  Branch (1557:14): [True: 104k, False: 257]
  ------------------
 1558|   104k|             static_cast<ptrdiff_t>(op + deferred_length) < op_limit_min_slop);
  ------------------
  |  Branch (1558:14): [True: 104k, False: 11]
  ------------------
 1559|  1.85k|  exit:
 1560|  1.85k|    ip--;
 1561|  1.85k|    assert(ip <= ip_limit);
  ------------------
  |  Branch (1561:5): [True: 1.85k, False: 0]
  ------------------
 1562|  1.85k|  }
 1563|       |  // If we deferred a copy then we can perform.  If we are up to date then we
 1564|       |  // might not have enough slop bytes and could run past the end.
 1565|  11.6k|  if (deferred_length) {
  ------------------
  |  Branch (1565:7): [True: 800, False: 10.8k]
  ------------------
 1566|    800|    MemCopy64(op_base + op, deferred_src, deferred_length);
 1567|    800|    op += deferred_length;
 1568|    800|    ClearDeferred(&deferred_src, &deferred_length, safe_source);
 1569|    800|  }
 1570|  11.6k|  return {ip, op};
 1571|  11.6k|}
_ZN6snappy28AdvanceToNextTagX86OptimizedEPPKhPm:
 1346|   212k|inline size_t AdvanceToNextTagX86Optimized(const uint8_t** ip_p, size_t* tag) {
 1347|   212k|  const uint8_t*& ip = *ip_p;
 1348|       |  // This section is crucial for the throughput of the decompression loop.
 1349|       |  // The latency of an iteration is fundamentally constrained by the
 1350|       |  // following data chain on ip.
 1351|       |  // ip -> c = Load(ip) -> ip1 = ip + 1 + (c & 3) -> ip = ip1 or ip2
 1352|       |  //                       ip2 = ip + 2 + (c >> 2)
 1353|       |  // This amounts to 8 cycles.
 1354|       |  // 5 (load) + 1 (c & 3) + 1 (lea ip1, [ip + (c & 3) + 1]) + 1 (cmov)
 1355|   212k|  size_t literal_len = *tag >> 2;
 1356|   212k|  size_t tag_type = *tag;
 1357|   212k|  bool is_literal;
 1358|   212k|#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
 1359|       |  // TODO clang misses the fact that the (c & 3) already correctly
 1360|       |  // sets the zero flag.
 1361|   212k|  asm("and $3, %k[tag_type]\n\t"
 1362|   212k|      : [tag_type] "+r"(tag_type), "=@ccz"(is_literal)
 1363|   212k|      :: "cc");
 1364|       |#else
 1365|       |  tag_type &= 3;
 1366|       |  is_literal = (tag_type == 0);
 1367|       |#endif
 1368|       |  // TODO
 1369|       |  // This is code is subtle. Loading the values first and then cmov has less
 1370|       |  // latency then cmov ip and then load. However clang would move the loads
 1371|       |  // in an optimization phase, volatile prevents this transformation.
 1372|       |  // Note that we have enough slop bytes (64) that the loads are always valid.
 1373|   212k|  size_t tag_literal =
 1374|   212k|      static_cast<const volatile uint8_t*>(ip)[1 + literal_len];
 1375|   212k|  size_t tag_copy = static_cast<const volatile uint8_t*>(ip)[tag_type];
 1376|   212k|  *tag = is_literal ? tag_literal : tag_copy;
  ------------------
  |  Branch (1376:10): [True: 6.33k, False: 206k]
  ------------------
 1377|   212k|  const uint8_t* ip_copy = ip + 1 + tag_type;
 1378|   212k|  const uint8_t* ip_literal = ip + 2 + literal_len;
 1379|   212k|  ip = is_literal ? ip_literal : ip_copy;
  ------------------
  |  Branch (1379:8): [True: 6.33k, False: 206k]
  ------------------
 1380|   212k|#if defined(__GNUC__) && defined(__x86_64__)
 1381|       |  // TODO Clang is "optimizing" zero-extension (a totally free
 1382|       |  // operation) this means that after the cmov of tag, it emits another movzb
 1383|       |  // tag, byte(tag). It really matters as it's on the core chain. This dummy
 1384|       |  // asm, persuades clang to do the zero-extension at the load (it's automatic)
 1385|       |  // removing the expensive movzb.
 1386|   212k|  asm("" ::"r"(tag_copy));
 1387|   212k|#endif
 1388|   212k|  return tag_type;
 1389|   212k|}
_ZN6snappy13ExtractOffsetEjm:
 1418|   212k|inline uint32_t ExtractOffset(uint32_t val, size_t tag_type) {
 1419|       |  // For Arm non-static storage works better. For x86 static storage is better.
 1420|       |  // TODO: Once the array is recognized as a register, improve the
 1421|       |  // readability for x86.
 1422|   212k|#if defined(__x86_64__)
 1423|   212k|  static constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
 1424|   212k|  uint16_t result;
 1425|   212k|  memcpy(&result,
 1426|   212k|         reinterpret_cast<const char*>(&kExtractMasksCombined) + 2 * tag_type,
 1427|   212k|         sizeof(result));
 1428|   212k|  return val & result;
 1429|       |  // For AArch64 and RISC-V, use a bit-twiddling trick to extract the mask from a
 1430|       |  // single combined constant instead of a lookup table. The constant packs multiple
 1431|       |  // 16-bit masks based on tag_type (see implementation below). The code calculates
 1432|       |  // the shift amount from tag_type, right-shifts the constant to move the desired
 1433|       |  // mask to the LSB position, then extracts it with & 0xFFFF. This branchless
 1434|       |  // approach is often more performant on modern CPUs.
 1435|       |#elif defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64))
 1436|       |  constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull;
 1437|       |  return val & static_cast<uint32_t>(
 1438|       |      (kExtractMasksCombined >> (tag_type * 16)) & 0xFFFF);
 1439|       |#else
 1440|       |  static constexpr uint32_t kExtractMasks[4] = {0, 0xFF, 0xFFFF, 0};
 1441|       |  return val & kExtractMasks[tag_type];
 1442|       |#endif
 1443|   212k|};
snappy.cc:_ZN6snappy12_GLOBAL__N_131Copy64BytesWithPatternExtensionEPcm:
  363|   195k|static inline bool Copy64BytesWithPatternExtension(char* dst, size_t offset) {
  364|       |#if SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  365|       |  if (SNAPPY_PREDICT_TRUE(offset <= 16)) {
  366|       |    switch (offset) {
  367|       |      case 0:
  368|       |        return false;
  369|       |      case 1: {
  370|       |        // TODO: Ideally we should memset, move back once the
  371|       |        // codegen issues are fixed.
  372|       |        V128 pattern = V128_DupChar(dst[-1]);
  373|       |        for (int i = 0; i < 4; i++) {
  374|       |          V128_StoreU(reinterpret_cast<V128*>(dst + 16 * i), pattern);
  375|       |        }
  376|       |        return true;
  377|       |      }
  378|       |      case 2:
  379|       |      case 4:
  380|       |      case 8:
  381|       |      case 16: {
  382|       |        V128 pattern = LoadPattern(dst - offset, offset);
  383|       |        for (int i = 0; i < 4; i++) {
  384|       |          V128_StoreU(reinterpret_cast<V128*>(dst + 16 * i), pattern);
  385|       |        }
  386|       |        return true;
  387|       |      }
  388|       |      default: {
  389|       |        auto pattern_and_reshuffle_mask =
  390|       |            LoadPatternAndReshuffleMask(dst - offset, offset);
  391|       |        V128 pattern = pattern_and_reshuffle_mask.first;
  392|       |        V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
  393|       |        for (int i = 0; i < 4; i++) {
  394|       |          V128_StoreU(reinterpret_cast<V128*>(dst + 16 * i), pattern);
  395|       |          pattern = V128_Shuffle(pattern, reshuffle_mask);
  396|       |        }
  397|       |        return true;
  398|       |      }
  399|       |    }
  400|       |  }
  401|       |#else
  402|   195k|  if (SNAPPY_PREDICT_TRUE(offset < 16)) {
  ------------------
  |  |   95|   195k|#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
  |  |  ------------------
  |  |  |  Branch (95:32): [True: 167k, False: 27.9k]
  |  |  ------------------
  ------------------
  403|   167k|    if (SNAPPY_PREDICT_FALSE(offset == 0)) return false;
  ------------------
  |  |   94|   167k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 22, False: 167k]
  |  |  ------------------
  ------------------
  404|       |    // Extend the pattern to the first 16 bytes.
  405|       |    // The simpler formulation of `dst[i - offset]` induces undefined behavior.
  406|  2.84M|    for (int i = 0; i < 16; i++) dst[i] = (dst - offset)[i];
  ------------------
  |  Branch (406:21): [True: 2.67M, False: 167k]
  ------------------
  407|       |    // Find a multiple of pattern >= 16.
  408|   167k|    static std::array<uint8_t, 16> pattern_sizes = []() {
  409|   167k|      std::array<uint8_t, 16> res;
  410|   167k|      for (int i = 1; i < 16; i++) res[i] = (16 / i + 1) * i;
  411|   167k|      return res;
  412|   167k|    }();
  413|   167k|    offset = pattern_sizes[offset];
  414|   669k|    for (int i = 1; i < 4; i++) {
  ------------------
  |  Branch (414:21): [True: 502k, False: 167k]
  ------------------
  415|   502k|      std::memcpy(dst + i * 16, dst + i * 16 - offset, 16);
  416|   502k|    }
  417|   167k|    return true;
  418|   167k|  }
  419|  27.9k|#endif  // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  420|       |
  421|       |  // Very rare.
  422|   139k|  for (int i = 0; i < 4; i++) {
  ------------------
  |  Branch (422:19): [True: 111k, False: 27.9k]
  ------------------
  423|   111k|    std::memcpy(dst + i * 16, dst + i * 16 - offset, 16);
  424|   111k|  }
  425|  27.9k|  return true;
  426|   195k|}
snappy.cc:_ZZN6snappy12_GLOBAL__N_131Copy64BytesWithPatternExtensionEPcmENKUlvE_clEv:
  408|      1|    static std::array<uint8_t, 16> pattern_sizes = []() {
  409|      1|      std::array<uint8_t, 16> res;
  410|     16|      for (int i = 1; i < 16; i++) res[i] = (16 / i + 1) * i;
  ------------------
  |  Branch (410:23): [True: 15, False: 1]
  ------------------
  411|      1|      return res;
  412|      1|    }();
snappy.cc:_ZN6snappyL15ExtractLowBytesERKji:
 1216|  7.49k|static inline uint32_t ExtractLowBytes(const uint32_t& v, int n) {
 1217|  7.49k|  assert(n >= 0);
  ------------------
  |  Branch (1217:3): [True: 7.49k, False: 0]
  ------------------
 1218|  7.49k|  assert(n <= 4);
  ------------------
  |  Branch (1218:3): [True: 7.49k, False: 0]
  ------------------
 1219|       |#if SNAPPY_HAVE_BMI2
 1220|       |  return _bzhi_u32(v, 8 * n);
 1221|       |#else
 1222|       |  // This needs to be wider than uint32_t otherwise `mask << 32` will be
 1223|       |  // undefined.
 1224|  7.49k|  uint64_t mask = 0xffffffff;
 1225|  7.49k|  return v & ~(mask << (8 * n));
 1226|  7.49k|#endif
 1227|  7.49k|}
snappy.cc:_ZN6snappy12_GLOBAL__N_115IncrementalCopyEPKcPcS3_S3_:
  432|  5.29k|                             char* const buf_limit) {
  433|       |#if SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  434|       |  constexpr int big_pattern_size_lower_bound = 16;
  435|       |#else
  436|  5.29k|  constexpr int big_pattern_size_lower_bound = 8;
  437|  5.29k|#endif
  438|       |
  439|       |  // Terminology:
  440|       |  //
  441|       |  // slop = buf_limit - op
  442|       |  // pat  = op - src
  443|       |  // len  = op_limit - op
  444|  5.29k|  assert(src < op);
  ------------------
  |  Branch (444:3): [True: 5.29k, False: 0]
  ------------------
  445|  5.29k|  assert(op < op_limit);
  ------------------
  |  Branch (445:3): [True: 5.29k, False: 0]
  ------------------
  446|  5.29k|  assert(op_limit <= buf_limit);
  ------------------
  |  Branch (446:3): [True: 5.29k, False: 0]
  ------------------
  447|       |  // NOTE: The copy tags use 3 or 6 bits to store the copy length, so len <= 64.
  448|  5.29k|  assert(op_limit - op <= 64);
  ------------------
  |  Branch (448:3): [True: 5.29k, False: 0]
  ------------------
  449|       |  // NOTE: In practice the compressor always emits len >= 4, so it is ok to
  450|       |  // assume that to optimize this function, but this is not guaranteed by the
  451|       |  // compression format, so we have to also handle len < 4 in case the input
  452|       |  // does not satisfy these conditions.
  453|       |
  454|  5.29k|  size_t pattern_size = op - src;
  455|       |  // The cases are split into different branches to allow the branch predictor,
  456|       |  // FDO, and static prediction hints to work better. For each input we list the
  457|       |  // ratio of invocations that match each condition.
  458|       |  //
  459|       |  // input        slop < 16   pat < 8  len > 16
  460|       |  // ------------------------------------------
  461|       |  // html|html4|cp   0%         1.01%    27.73%
  462|       |  // urls            0%         0.88%    14.79%
  463|       |  // jpg             0%        64.29%     7.14%
  464|       |  // pdf             0%         2.56%    58.06%
  465|       |  // txt[1-4]        0%         0.23%     0.97%
  466|       |  // pb              0%         0.96%    13.88%
  467|       |  // bin             0.01%     22.27%    41.17%
  468|       |  //
  469|       |  // It is very rare that we don't have enough slop for doing block copies. It
  470|       |  // is also rare that we need to expand a pattern. Small patterns are common
  471|       |  // for incompressible formats and for those we are plenty fast already.
  472|       |  // Lengths are normally not greater than 16 but they vary depending on the
  473|       |  // input. In general if we always predict len <= 16 it would be an ok
  474|       |  // prediction.
  475|       |  //
  476|       |  // In order to be fast we want a pattern >= 16 bytes (or 8 bytes in non-SSE)
  477|       |  // and an unrolled loop copying 1x 16 bytes (or 2x 8 bytes in non-SSE) at a
  478|       |  // time.
  479|       |
  480|       |  // Handle the uncommon case where pattern is less than 16 (or 8 in non-SSE)
  481|       |  // bytes.
  482|  5.29k|  if (pattern_size < big_pattern_size_lower_bound) {
  ------------------
  |  Branch (482:7): [True: 4.07k, False: 1.22k]
  ------------------
  483|       |#if SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  484|       |    // Load the first eight bytes into an 128-bit XMM register, then use PSHUFB
  485|       |    // to permute the register's contents in-place into a repeating sequence of
  486|       |    // the first "pattern_size" bytes.
  487|       |    // For example, suppose:
  488|       |    //    src       == "abc"
  489|       |    //    op        == op + 3
  490|       |    // After V128_Shuffle(), "pattern" will have five copies of "abc"
  491|       |    // followed by one byte of slop: abcabcabcabcabca.
  492|       |    //
  493|       |    // The non-SSE fallback implementation suffers from store-forwarding stalls
  494|       |    // because its loads and stores partly overlap. By expanding the pattern
  495|       |    // in-place, we avoid the penalty.
  496|       |
  497|       |    // Typically, the op_limit is the gating factor so try to simplify the loop
  498|       |    // based on that.
  499|       |    if (SNAPPY_PREDICT_TRUE(op_limit <= buf_limit - 15)) {
  500|       |      auto pattern_and_reshuffle_mask =
  501|       |          LoadPatternAndReshuffleMask(src, pattern_size);
  502|       |      V128 pattern = pattern_and_reshuffle_mask.first;
  503|       |      V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
  504|       |      // There is at least one, and at most four 16-byte blocks. Writing four
  505|       |      // conditionals instead of a loop allows FDO to layout the code with
  506|       |      // respect to the actual probabilities of each length.
  507|       |      // TODO: Replace with loop with trip count hint.
  508|       |      V128_StoreU(reinterpret_cast<V128*>(op), pattern);
  509|       |
  510|       |      if (op + 16 < op_limit) {
  511|       |        pattern = V128_Shuffle(pattern, reshuffle_mask);
  512|       |        V128_StoreU(reinterpret_cast<V128*>(op + 16), pattern);
  513|       |      }
  514|       |      if (op + 32 < op_limit) {
  515|       |        pattern = V128_Shuffle(pattern, reshuffle_mask);
  516|       |        V128_StoreU(reinterpret_cast<V128*>(op + 32), pattern);
  517|       |      }
  518|       |      if (op + 48 < op_limit) {
  519|       |        pattern = V128_Shuffle(pattern, reshuffle_mask);
  520|       |        V128_StoreU(reinterpret_cast<V128*>(op + 48), pattern);
  521|       |      }
  522|       |      return op_limit;
  523|       |    }
  524|       |    char* const op_end = buf_limit - 15;
  525|       |    if (SNAPPY_PREDICT_TRUE(op < op_end)) {
  526|       |      auto pattern_and_reshuffle_mask =
  527|       |          LoadPatternAndReshuffleMask(src, pattern_size);
  528|       |      V128 pattern = pattern_and_reshuffle_mask.first;
  529|       |      V128 reshuffle_mask = pattern_and_reshuffle_mask.second;
  530|       |      // This code path is relatively cold however so we save code size
  531|       |      // by avoiding unrolling and vectorizing.
  532|       |      //
  533|       |      // TODO: Remove pragma when when cold regions don't get
  534|       |      // vectorized or unrolled.
  535|       |#ifdef __clang__
  536|       |#pragma clang loop unroll(disable)
  537|       |#endif
  538|       |      do {
  539|       |        V128_StoreU(reinterpret_cast<V128*>(op), pattern);
  540|       |        pattern = V128_Shuffle(pattern, reshuffle_mask);
  541|       |        op += 16;
  542|       |      } while (SNAPPY_PREDICT_TRUE(op < op_end));
  543|       |    }
  544|       |    return IncrementalCopySlow(op - pattern_size, op, op_limit);
  545|       |#else   // !SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  546|       |    // If plenty of buffer space remains, expand the pattern to at least 8
  547|       |    // bytes. The way the following loop is written, we need 8 bytes of buffer
  548|       |    // space if pattern_size >= 4, 11 bytes if pattern_size is 1 or 3, and 10
  549|       |    // bytes if pattern_size is 2.  Precisely encoding that is probably not
  550|       |    // worthwhile; instead, invoke the slow path if we cannot write 11 bytes
  551|       |    // (because 11 are required in the worst case).
  552|  4.07k|    if (SNAPPY_PREDICT_TRUE(op <= buf_limit - 11)) {
  ------------------
  |  |   95|  4.07k|#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
  |  |  ------------------
  |  |  |  Branch (95:32): [True: 4.00k, False: 71]
  |  |  ------------------
  ------------------
  553|  15.2k|      while (pattern_size < 8) {
  ------------------
  |  Branch (553:14): [True: 11.2k, False: 4.00k]
  ------------------
  554|  11.2k|        UnalignedCopy64(src, op);
  555|  11.2k|        op += pattern_size;
  556|  11.2k|        pattern_size *= 2;
  557|  11.2k|      }
  558|  4.00k|      if (SNAPPY_PREDICT_TRUE(op >= op_limit)) return op_limit;
  ------------------
  |  |   95|  4.00k|#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
  |  |  ------------------
  |  |  |  Branch (95:32): [True: 971, False: 3.02k]
  |  |  ------------------
  ------------------
  559|  4.00k|    } else {
  560|     71|      return IncrementalCopySlow(src, op, op_limit);
  561|     71|    }
  562|  4.07k|#endif  // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
  563|  4.07k|  }
  564|  5.29k|  assert(pattern_size >= big_pattern_size_lower_bound);
  ------------------
  |  Branch (564:3): [True: 4.25k, False: 0]
  ------------------
  565|  4.25k|  constexpr bool use_16bytes_chunk = big_pattern_size_lower_bound == 16;
  566|       |
  567|       |  // Copy 1x 16 bytes (or 2x 8 bytes in non-SSE) at a time. Because op - src can
  568|       |  // be < 16 in non-SSE, a single UnalignedCopy128 might overwrite data in op.
  569|       |  // UnalignedCopy64 is safe because expanding the pattern to at least 8 bytes
  570|       |  // guarantees that op - src >= 8.
  571|       |  //
  572|       |  // Typically, the op_limit is the gating factor so try to simplify the loop
  573|       |  // based on that.
  574|  4.25k|  if (SNAPPY_PREDICT_TRUE(op_limit <= buf_limit - 15)) {
  ------------------
  |  |   95|  4.25k|#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
  |  |  ------------------
  |  |  |  Branch (95:32): [True: 4.12k, False: 130]
  |  |  ------------------
  ------------------
  575|       |    // There is at least one, and at most four 16-byte blocks. Writing four
  576|       |    // conditionals instead of a loop allows FDO to layout the code with respect
  577|       |    // to the actual probabilities of each length.
  578|       |    // TODO: Replace with loop with trip count hint.
  579|  4.12k|    ConditionalUnalignedCopy128<use_16bytes_chunk>(src, op);
  580|  4.12k|    if (op + 16 < op_limit) {
  ------------------
  |  Branch (580:9): [True: 3.28k, False: 839]
  ------------------
  581|  3.28k|      ConditionalUnalignedCopy128<use_16bytes_chunk>(src + 16, op + 16);
  582|  3.28k|    }
  583|  4.12k|    if (op + 32 < op_limit) {
  ------------------
  |  Branch (583:9): [True: 3.19k, False: 928]
  ------------------
  584|  3.19k|      ConditionalUnalignedCopy128<use_16bytes_chunk>(src + 32, op + 32);
  585|  3.19k|    }
  586|  4.12k|    if (op + 48 < op_limit) {
  ------------------
  |  Branch (586:9): [True: 3.14k, False: 979]
  ------------------
  587|  3.14k|      ConditionalUnalignedCopy128<use_16bytes_chunk>(src + 48, op + 48);
  588|  3.14k|    }
  589|  4.12k|    return op_limit;
  590|  4.12k|  }
  591|       |
  592|       |  // Fall back to doing as much as we can with the available slop in the
  593|       |  // buffer. This code path is relatively cold however so we save code size by
  594|       |  // avoiding unrolling and vectorizing.
  595|       |  //
  596|       |  // TODO: Remove pragma when when cold regions don't get vectorized
  597|       |  // or unrolled.
  598|    130|#ifdef __clang__
  599|    130|#pragma clang loop unroll(disable)
  600|    130|#endif
  601|    183|  for (char* op_end = buf_limit - 16; op < op_end; op += 16, src += 16) {
  ------------------
  |  Branch (601:39): [True: 53, False: 130]
  ------------------
  602|     53|    ConditionalUnalignedCopy128<use_16bytes_chunk>(src, op);
  603|     53|  }
  604|    130|  if (op >= op_limit) return op_limit;
  ------------------
  |  Branch (604:7): [True: 14, False: 116]
  ------------------
  605|       |
  606|       |  // We only take this branch if we didn't have enough slop and we can do a
  607|       |  // single 8 byte copy.
  608|    116|  if (SNAPPY_PREDICT_FALSE(op <= buf_limit - 8)) {
  ------------------
  |  |   94|    116|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 67, False: 49]
  |  |  ------------------
  ------------------
  609|     67|    UnalignedCopy64(src, op);
  610|     67|    src += 8;
  611|     67|    op += 8;
  612|     67|  }
  613|    116|  return IncrementalCopySlow(src, op, op_limit);
  614|    130|}
snappy.cc:_ZN6snappy12_GLOBAL__N_115UnalignedCopy64EPKvPv:
  229|  38.8k|void UnalignedCopy64(const void* src, void* dst) {
  230|  38.8k|  char tmp[8];
  231|  38.8k|  std::memcpy(tmp, src, 8);
  232|  38.8k|  std::memcpy(dst, tmp, 8);
  233|  38.8k|}
snappy.cc:_ZN6snappy12_GLOBAL__N_119IncrementalCopySlowEPKcPcS3_:
  266|    187|                                 char* const op_limit) {
  267|       |  // TODO: Remove pragma when LLVM is aware this
  268|       |  // function is only called in cold regions and when cold regions don't get
  269|       |  // vectorized or unrolled.
  270|    187|#ifdef __clang__
  271|    187|#pragma clang loop unroll(disable)
  272|    187|#endif
  273|    480|  while (op < op_limit) {
  ------------------
  |  Branch (273:10): [True: 293, False: 187]
  ------------------
  274|    293|    *op++ = *src++;
  275|    293|  }
  276|    187|  return op_limit;
  277|    187|}
snappy.cc:_ZN6snappy12_GLOBAL__N_127ConditionalUnalignedCopy128ILb0EEEvPKcPc:
  245|  13.7k|inline void ConditionalUnalignedCopy128(const char* src, char* dst) {
  246|  13.7k|  if (use_16bytes_chunk) {
  ------------------
  |  Branch (246:7): [Folded, False: 13.7k]
  ------------------
  247|      0|    UnalignedCopy128(src, dst);
  248|  13.7k|  } else {
  249|  13.7k|    UnalignedCopy64(src, dst);
  250|  13.7k|    UnalignedCopy64(src + 8, dst + 8);
  251|  13.7k|  }
  252|  13.7k|}
snappy.cc:_ZN6snappyL6ReportEiPKcmm:
 1152|  1.13k|compressed_size, size_t uncompressed_size) {
 1153|       |  // TODO: Switch to [[maybe_unused]] when we can assume C++17.
 1154|  1.13k|  (void)token;
 1155|  1.13k|  (void)algorithm;
 1156|  1.13k|  (void)compressed_size;
 1157|  1.13k|  (void)uncompressed_size;
 1158|  1.13k|}
_ZNK6snappy18SnappyDecompressor3eofEv:
 1608|  1.13k|  bool eof() const { return eof_; }
snappy.cc:_ZN6snappyL18InternalUncompressINS_17SnappyArrayWriterEEEbPNS_6SourceEPT_:
 1851|  1.13k|static bool InternalUncompress(Source* r, Writer* writer) {
 1852|       |  // Read the uncompressed length from the front of the compressed input
 1853|  1.13k|  SnappyDecompressor decompressor(r);
 1854|  1.13k|  uint32_t uncompressed_len = 0;
 1855|  1.13k|  if (!decompressor.ReadUncompressedLength(&uncompressed_len)) return false;
  ------------------
  |  Branch (1855:7): [True: 0, False: 1.13k]
  ------------------
 1856|       |
 1857|  1.13k|  return InternalUncompressAllTags(&decompressor, writer, r->Available(),
 1858|  1.13k|                                   uncompressed_len);
 1859|  1.13k|}
snappy.cc:_ZN6snappyL25InternalUncompressAllTagsINS_17SnappyArrayWriterEEEbPNS_18SnappyDecompressorEPT_jj:
 1864|  1.13k|                                      uint32_t uncompressed_len) {
 1865|  1.13k|    int token = 0;
 1866|       |
 1867|  1.13k|  writer->SetExpectedLength(uncompressed_len);
 1868|       |
 1869|       |  // Process the entire input
 1870|  1.13k|  decompressor->DecompressAllTags(writer);
 1871|  1.13k|  writer->Flush();
 1872|  1.13k|  Report(token, "snappy_uncompress", compressed_len, uncompressed_len);
 1873|  1.13k|  return (decompressor->eof() && writer->CheckLength());
  ------------------
  |  Branch (1873:11): [True: 309, False: 823]
  |  Branch (1873:34): [True: 16, False: 293]
  ------------------
 1874|  1.13k|}
_ZN6snappy17SnappyArrayWriter17SetExpectedLengthEm:
 2308|  1.13k|  inline void SetExpectedLength(size_t len) {
 2309|  1.13k|    op_limit_ = op_ + len;
 2310|       |    // Prevent pointer from being past the buffer.
 2311|  1.13k|    op_limit_min_slop_ = op_limit_ - std::min<size_t>(kSlopBytes - 1, len);
 2312|  1.13k|  }
_ZN6snappy18SnappyDecompressor17DecompressAllTagsINS_17SnappyArrayWriterEEEvPT_:
 1643|  1.13k|  DecompressAllTags(Writer* writer) {
 1644|  1.13k|    const char* ip = ip_;
 1645|  1.13k|    ResetLimit(ip);
 1646|  1.13k|    auto op = writer->GetOutputPtr();
 1647|       |    // We could have put this refill fragment only at the beginning of the loop.
 1648|       |    // However, duplicating it at the end of each branch gives the compiler more
 1649|       |    // scope to optimize the <ip_limit_ - ip> expression based on the local
 1650|       |    // context, which overall increases speed.
 1651|  1.13k|#define MAYBE_REFILL()                                      \
 1652|  1.13k|  if (SNAPPY_PREDICT_FALSE(ip >= ip_limit_min_maxtaglen_)) { \
 1653|  1.13k|    ip_ = ip;                                               \
 1654|  1.13k|    if (SNAPPY_PREDICT_FALSE(!RefillTag())) goto exit;       \
 1655|  1.13k|    ip = ip_;                                               \
 1656|  1.13k|    ResetLimit(ip);                                         \
 1657|  1.13k|  }                                                         \
 1658|  1.13k|  preload = static_cast<uint8_t>(*ip)
 1659|       |
 1660|       |    // At the start of the for loop below the least significant byte of preload
 1661|       |    // contains the tag.
 1662|  1.13k|    uint32_t preload;
 1663|  1.13k|    MAYBE_REFILL();
  ------------------
  |  | 1652|  1.13k|  if (SNAPPY_PREDICT_FALSE(ip >= ip_limit_min_maxtaglen_)) { \
  |  |  ------------------
  |  |  |  |   94|  1.13k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 1.13k, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1653|  1.13k|    ip_ = ip;                                               \
  |  | 1654|  1.13k|    if (SNAPPY_PREDICT_FALSE(!RefillTag())) goto exit;       \
  |  |  ------------------
  |  |  |  |   94|  1.13k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 67, False: 1.06k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1655|  1.13k|    ip = ip_;                                               \
  |  | 1656|  1.06k|    ResetLimit(ip);                                         \
  |  | 1657|  1.06k|  }                                                         \
  |  | 1658|  1.13k|  preload = static_cast<uint8_t>(*ip)
  ------------------
 1664|  11.7k|    for (;;) {
 1665|  11.7k|      {
 1666|  11.7k|        ptrdiff_t op_limit_min_slop;
 1667|  11.7k|        auto op_base = writer->GetBase(&op_limit_min_slop);
 1668|  11.7k|        if (op_base) {
  ------------------
  |  Branch (1668:13): [True: 11.6k, False: 45]
  ------------------
 1669|  11.6k|          auto res =
 1670|  11.6k|              DecompressBranchless(reinterpret_cast<const uint8_t*>(ip),
 1671|  11.6k|                                   reinterpret_cast<const uint8_t*>(ip_limit_),
 1672|  11.6k|                                   op - op_base, op_base, op_limit_min_slop);
 1673|  11.6k|          ip = reinterpret_cast<const char*>(res.first);
 1674|  11.6k|          op = op_base + res.second;
 1675|  11.6k|          MAYBE_REFILL();
  ------------------
  |  | 1652|  11.6k|  if (SNAPPY_PREDICT_FALSE(ip >= ip_limit_min_maxtaglen_)) { \
  |  |  ------------------
  |  |  |  |   94|  11.6k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 437, False: 11.2k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1653|    437|    ip_ = ip;                                               \
  |  | 1654|    437|    if (SNAPPY_PREDICT_FALSE(!RefillTag())) goto exit;       \
  |  |  ------------------
  |  |  |  |   94|    437|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 0, False: 437]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1655|    437|    ip = ip_;                                               \
  |  | 1656|    437|    ResetLimit(ip);                                         \
  |  | 1657|    437|  }                                                         \
  |  | 1658|  11.6k|  preload = static_cast<uint8_t>(*ip)
  ------------------
 1676|  11.6k|        }
 1677|  11.7k|      }
 1678|  11.7k|      const uint8_t c = static_cast<uint8_t>(preload);
 1679|  11.7k|      ip++;
 1680|       |
 1681|       |      // Ratio of iterations that have LITERAL vs non-LITERAL for different
 1682|       |      // inputs.
 1683|       |      //
 1684|       |      // input          LITERAL  NON_LITERAL
 1685|       |      // -----------------------------------
 1686|       |      // html|html4|cp   23%        77%
 1687|       |      // urls            36%        64%
 1688|       |      // jpg             47%        53%
 1689|       |      // pdf             19%        81%
 1690|       |      // txt[1-4]        25%        75%
 1691|       |      // pb              24%        76%
 1692|       |      // bin             24%        76%
 1693|  11.7k|      if (SNAPPY_PREDICT_FALSE((c & 0x3) == LITERAL)) {
  ------------------
  |  |   94|  11.7k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 4.63k, False: 7.10k]
  |  |  ------------------
  ------------------
 1694|  4.63k|        size_t literal_length = (c >> 2) + 1u;
 1695|  4.63k|        if (writer->TryFastAppend(ip, ip_limit_ - ip, literal_length, &op)) {
  ------------------
  |  Branch (1695:13): [True: 1.92k, False: 2.70k]
  ------------------
 1696|  1.92k|          assert(literal_length < 61);
  ------------------
  |  Branch (1696:11): [True: 1.92k, False: 0]
  ------------------
 1697|  1.92k|          ip += literal_length;
 1698|       |          // NOTE: There is no MAYBE_REFILL() here, as TryFastAppend()
 1699|       |          // will not return true unless there's already at least five spare
 1700|       |          // bytes in addition to the literal.
 1701|  1.92k|          preload = static_cast<uint8_t>(*ip);
 1702|  1.92k|          continue;
 1703|  1.92k|        }
 1704|  2.70k|        if (SNAPPY_PREDICT_FALSE(literal_length >= 61)) {
  ------------------
  |  |   94|  2.70k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 1.64k, False: 1.06k]
  |  |  ------------------
  ------------------
 1705|       |          // Long literal.
 1706|  1.64k|          const size_t literal_length_length = literal_length - 60;
 1707|       |          // NOTE: literal_length might be equal 2^32 (i.e. ExtractLowBytes
 1708|       |          // returns 0xFFFFFFFF); this is implicitly invalid stream (since
 1709|       |          // uncompressed length is capped with 0xFFFFFFFF); for performance we
 1710|       |          // do not check for this case here.
 1711|  1.64k|          literal_length =
 1712|  1.64k|              ExtractLowBytes(LittleEndian::Load32(ip), literal_length_length) +
 1713|  1.64k|              size_t{1};
 1714|  1.64k|          ip += literal_length_length;
 1715|  1.64k|        }
 1716|       |
 1717|  2.70k|        size_t avail = ip_limit_ - ip;
 1718|  2.70k|        while (avail < literal_length) {
  ------------------
  |  Branch (1718:16): [True: 167, False: 2.54k]
  ------------------
 1719|    167|          if (!writer->Append(ip, avail, &op)) goto exit;
  ------------------
  |  Branch (1719:15): [True: 25, False: 142]
  ------------------
 1720|    142|          literal_length -= avail;
 1721|    142|          reader_->Skip(peeked_);
 1722|    142|          size_t n;
 1723|    142|          ip = reader_->Peek(&n);
 1724|    142|          avail = n;
 1725|    142|          peeked_ = avail;
 1726|    142|          if (avail == 0) goto exit;
  ------------------
  |  Branch (1726:15): [True: 142, False: 0]
  ------------------
 1727|      0|          ip_limit_ = ip + avail;
 1728|      0|          ResetLimit(ip);
 1729|      0|        }
 1730|  2.54k|        if (!writer->Append(ip, literal_length, &op)) goto exit;
  ------------------
  |  Branch (1730:13): [True: 64, False: 2.47k]
  ------------------
 1731|  2.47k|        ip += literal_length;
 1732|  2.47k|        MAYBE_REFILL();
  ------------------
  |  | 1652|  2.47k|  if (SNAPPY_PREDICT_FALSE(ip >= ip_limit_min_maxtaglen_)) { \
  |  |  ------------------
  |  |  |  |   94|  2.47k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 178, False: 2.29k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1653|    178|    ip_ = ip;                                               \
  |  | 1654|    178|    if (SNAPPY_PREDICT_FALSE(!RefillTag())) goto exit;       \
  |  |  ------------------
  |  |  |  |   94|    178|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 48, False: 130]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1655|    178|    ip = ip_;                                               \
  |  | 1656|    130|    ResetLimit(ip);                                         \
  |  | 1657|    130|  }                                                         \
  |  | 1658|  2.47k|  preload = static_cast<uint8_t>(*ip)
  ------------------
 1733|  7.10k|      } else {
 1734|  7.10k|        if (SNAPPY_PREDICT_FALSE((c & 3) == COPY_4_BYTE_OFFSET)) {
  ------------------
  |  |   94|  7.10k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 1.25k, False: 5.85k]
  |  |  ------------------
  ------------------
 1735|  1.25k|          const size_t copy_offset = LittleEndian::Load32(ip);
 1736|  1.25k|          const size_t length = (c >> 2) + 1;
 1737|  1.25k|          ip += 4;
 1738|       |
 1739|  1.25k|          if (!writer->AppendFromSelf(copy_offset, length, &op)) goto exit;
  ------------------
  |  Branch (1739:15): [True: 202, False: 1.05k]
  ------------------
 1740|  5.85k|        } else {
 1741|  5.85k|          const ptrdiff_t entry = kLengthMinusOffset[c];
 1742|  5.85k|          preload = LittleEndian::Load32(ip);
 1743|  5.85k|          const uint32_t trailer = ExtractLowBytes(preload, c & 3);
 1744|  5.85k|          const uint32_t length = entry & 0xff;
 1745|  5.85k|          assert(length > 0);
  ------------------
  |  Branch (1745:11): [True: 5.85k, False: 0]
  ------------------
 1746|       |
 1747|       |          // copy_offset/256 is encoded in bits 8..10.  By just fetching
 1748|       |          // those bits, we get copy_offset (since the bit-field starts at
 1749|       |          // bit 8).
 1750|  5.85k|          const uint32_t copy_offset = trailer - entry + length;
 1751|  5.85k|          if (!writer->AppendFromSelf(copy_offset, length, &op)) goto exit;
  ------------------
  |  Branch (1751:15): [True: 375, False: 5.47k]
  ------------------
 1752|       |
 1753|  5.47k|          ip += (c & 3);
 1754|       |          // By using the result of the previous load we reduce the critical
 1755|       |          // dependency chain of ip to 4 cycles.
 1756|  5.47k|          preload >>= (c & 3) * 8;
 1757|  5.47k|          if (ip < ip_limit_min_maxtaglen_) continue;
  ------------------
  |  Branch (1757:15): [True: 5.16k, False: 314]
  ------------------
 1758|  5.47k|        }
 1759|  2.52k|        MAYBE_REFILL();
  ------------------
  |  | 1652|  1.36k|  if (SNAPPY_PREDICT_FALSE(ip >= ip_limit_min_maxtaglen_)) { \
  |  |  ------------------
  |  |  |  |   94|  1.36k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 389, False: 976]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1653|    389|    ip_ = ip;                                               \
  |  | 1654|    389|    if (SNAPPY_PREDICT_FALSE(!RefillTag())) goto exit;       \
  |  |  ------------------
  |  |  |  |   94|    389|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (94:33): [True: 209, False: 180]
  |  |  |  |  ------------------
  |  |  ------------------
  |  | 1655|    389|    ip = ip_;                                               \
  |  | 1656|    180|    ResetLimit(ip);                                         \
  |  | 1657|    180|  }                                                         \
  |  | 1658|  1.36k|  preload = static_cast<uint8_t>(*ip)
  ------------------
 1760|  2.52k|      }
 1761|  11.7k|    }
 1762|      0|#undef MAYBE_REFILL
 1763|  1.13k|  exit:
 1764|  1.13k|    writer->SetOutputPtr(op);
 1765|  1.13k|  }
_ZN6snappy17SnappyArrayWriter12GetOutputPtrEv:
 2316|  1.13k|  char* GetOutputPtr() { return op_; }
_ZN6snappy17SnappyArrayWriter7GetBaseEPl:
 2317|  11.7k|  char* GetBase(ptrdiff_t* op_limit_min_slop) {
 2318|  11.7k|    *op_limit_min_slop = op_limit_min_slop_ - base_;
 2319|  11.7k|    return base_;
 2320|  11.7k|  }
_ZN6snappy17SnappyArrayWriter13TryFastAppendEPKcmmPPc:
 2333|  4.63k|                            char** op_p) {
 2334|  4.63k|    char* op = *op_p;
 2335|  4.63k|    const size_t space_left = op_limit_ - op;
 2336|  4.63k|    if (len <= 16 && available >= 16 + kMaximumTagLength && space_left >= 16) {
  ------------------
  |  Branch (2336:9): [True: 2.88k, False: 1.74k]
  |  Branch (2336:22): [True: 2.29k, False: 590]
  |  Branch (2336:61): [True: 1.92k, False: 369]
  ------------------
 2337|       |      // Fast path, used for the majority (about 95%) of invocations.
 2338|  1.92k|      UnalignedCopy128(ip, op);
 2339|  1.92k|      *op_p = op + len;
 2340|  1.92k|      return true;
 2341|  2.70k|    } else {
 2342|  2.70k|      return false;
 2343|  2.70k|    }
 2344|  4.63k|  }
_ZN6snappy17SnappyArrayWriter6AppendEPKcmPPc:
 2323|  2.70k|  inline bool Append(const char* ip, size_t len, char** op_p) {
 2324|  2.70k|    char* op = *op_p;
 2325|  2.70k|    const size_t space_left = op_limit_ - op;
 2326|  2.70k|    if (space_left < len) return false;
  ------------------
  |  Branch (2326:9): [True: 89, False: 2.61k]
  ------------------
 2327|  2.61k|    std::memcpy(op, ip, len);
 2328|  2.61k|    *op_p = op + len;
 2329|  2.61k|    return true;
 2330|  2.70k|  }
_ZN6snappy17SnappyArrayWriter14AppendFromSelfEmmPPc:
 2347|  7.10k|  inline bool AppendFromSelf(size_t offset, size_t len, char** op_p) {
 2348|  7.10k|    assert(len > 0);
  ------------------
  |  Branch (2348:5): [True: 7.10k, False: 0]
  ------------------
 2349|  7.10k|    char* const op = *op_p;
 2350|  7.10k|    assert(op >= base_);
  ------------------
  |  Branch (2350:5): [True: 7.10k, False: 0]
  ------------------
 2351|  7.10k|    char* const op_end = op + len;
 2352|       |
 2353|       |    // Check if we try to append from before the start of the buffer.
 2354|  7.10k|    if (SNAPPY_PREDICT_FALSE(static_cast<size_t>(op - base_) < offset))
  ------------------
  |  |   94|  7.10k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 418, False: 6.68k]
  |  |  ------------------
  ------------------
 2355|    418|      return false;
 2356|       |
 2357|  6.68k|    if (SNAPPY_PREDICT_FALSE((kSlopBytes < 64 && len > kSlopBytes) ||
  ------------------
  |  |   94|  32.7k|#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
  |  |  ------------------
  |  |  |  Branch (94:33): [True: 5.45k, False: 1.23k]
  |  |  |  Branch (94:51): [Folded, False: 6.68k]
  |  |  |  Branch (94:51): [True: 0, False: 0]
  |  |  |  Branch (94:51): [True: 643, False: 6.04k]
  |  |  |  Branch (94:51): [True: 4.80k, False: 1.23k]
  |  |  ------------------
  ------------------
 2358|  6.68k|                            op >= op_limit_min_slop_ || offset < len)) {
 2359|  5.45k|      if (op_end > op_limit_ || offset == 0) return false;
  ------------------
  |  Branch (2359:11): [True: 20, False: 5.43k]
  |  Branch (2359:33): [True: 139, False: 5.29k]
  ------------------
 2360|  5.29k|      *op_p = IncrementalCopy(op - offset, op, op_end, op_limit_);
 2361|  5.29k|      return true;
 2362|  5.45k|    }
 2363|  1.23k|    std::memmove(op, op - offset, kSlopBytes);
 2364|  1.23k|    *op_p = op_end;
 2365|  1.23k|    return true;
 2366|  6.68k|  }
_ZN6snappy17SnappyArrayWriter12SetOutputPtrEPc:
 2321|  1.13k|  void SetOutputPtr(char* op) { op_ = op; }
_ZN6snappy17SnappyArrayWriter5FlushEv:
 2371|  1.13k|  inline void Flush() {}
_ZNK6snappy17SnappyArrayWriter11CheckLengthEv:
 2314|    309|  inline bool CheckLength() const { return op_ == op_limit_; }

LLVMFuzzerTestOneInput:
   40|  1.19k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   41|  1.19k|  std::string input(reinterpret_cast<const char*>(data), size);
   42|       |
   43|       |  // Avoid self-crafted decompression bombs.
   44|  1.19k|  size_t uncompressed_size;
   45|  1.19k|  constexpr size_t kMaxUncompressedSize = 1 << 20;
   46|  1.19k|  bool get_uncompressed_length_succeeded = snappy::GetUncompressedLength(
   47|  1.19k|      input.data(), input.size(), &uncompressed_size);
   48|  1.19k|  if (!get_uncompressed_length_succeeded ||
  ------------------
  |  Branch (48:7): [True: 50, False: 1.14k]
  ------------------
   49|  1.14k|      (uncompressed_size > kMaxUncompressedSize)) {
  ------------------
  |  Branch (49:7): [True: 14, False: 1.13k]
  ------------------
   50|     64|    return 0;
   51|     64|  }
   52|       |
   53|  1.13k|  std::string uncompressed;
   54|       |  // The return value of snappy::Uncompress() is ignored because decompression
   55|       |  // will fail on invalid inputs.
   56|  1.13k|  snappy::Uncompress(input.data(), input.size(), &uncompressed);
   57|  1.13k|  return 0;
   58|  1.19k|}

