_Z29get_supported_implementationsv:
   26|  2.23k|get_supported_implementations() {
   27|  2.23k|  static const auto impl = []() -> auto {
   28|  2.23k|    std::vector<const simdutf::implementation*> ret;
   29|  2.23k|    for (auto e : simdutf::get_available_implementations()) {
   30|  2.23k|      std::cerr << "implementation " << e->name() << " is available? "
   31|  2.23k|                << e->supported_by_runtime_system() << '\n';
   32|  2.23k|      if (e->supported_by_runtime_system()) {
   33|  2.23k|        ret.push_back(e);
   34|  2.23k|      }
   35|  2.23k|    }
   36|  2.23k|    return ret;
   37|  2.23k|  }();
   38|  2.23k|  return {impl.data(), impl.size()};
   39|  2.23k|}
_ZZ29get_supported_implementationsvENKUlvE_clEv:
   27|      1|  static const auto impl = []() -> auto {
   28|      1|    std::vector<const simdutf::implementation*> ret;
   29|      4|    for (auto e : simdutf::get_available_implementations()) {
  ------------------
  |  Branch (29:17): [True: 4, False: 1]
  ------------------
   30|      4|      std::cerr << "implementation " << e->name() << " is available? "
   31|      4|                << e->supported_by_runtime_system() << '\n';
   32|      4|      if (e->supported_by_runtime_system()) {
  ------------------
  |  Branch (32:11): [True: 3, False: 1]
  ------------------
   33|      3|        ret.push_back(e);
   34|      3|      }
   35|      4|    }
   36|      1|    return ret;
   37|      1|  }();
_ZneRKN7simdutf6resultES2_:
   42|  4.46k|inline bool operator!=(const simdutf::result& a, const simdutf::result& b) {
   43|  4.46k|  return a.count != b.count || a.error != b.error;
  ------------------
  |  Branch (43:10): [True: 0, False: 4.46k]
  |  Branch (43:32): [True: 0, False: 4.46k]
  ------------------
   44|  4.46k|}

LLVMFuzzerTestOneInput:
  211|  2.23k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  212|       |  // First 4 bytes: action selector + alignment padding.
  213|  2.23k|  if (size < 4) {
  ------------------
  |  Branch (213:7): [True: 2, False: 2.23k]
  ------------------
  214|      2|    return 0;
  215|      2|  }
  216|  2.23k|  constexpr auto Ncases = 2u;
  217|  2.23k|  constexpr auto actionmask = std::bit_ceil(Ncases) - 1;
  218|  2.23k|  const auto action = data[0] & actionmask;
  219|       |
  220|       |  // Advance by 4 so the remaining data is aligned to char16_t.
  221|  2.23k|  data += 4;
  222|  2.23k|  size -= 4;
  223|       |
  224|  2.23k|  const std::span<const char16_t> u16data{
  225|  2.23k|      reinterpret_cast<const char16_t*>(data), size / sizeof(char16_t)};
  226|       |
  227|  2.23k|  switch (action) {
  ------------------
  |  Branch (227:11): [True: 2.23k, False: 0]
  ------------------
  228|  1.11k|  case 0:
  ------------------
  |  Branch (228:3): [True: 1.11k, False: 1.12k]
  ------------------
  229|  1.11k|    test_utf16le_with_replacement(u16data);
  230|  1.11k|    break;
  231|  1.12k|  case 1:
  ------------------
  |  Branch (231:3): [True: 1.12k, False: 1.11k]
  ------------------
  232|  1.12k|    test_utf16be_with_replacement(u16data);
  233|  1.12k|    break;
  234|  2.23k|  }
  235|       |
  236|  2.23k|  return 0;
  237|  2.23k|}
with_replacement.cpp:_ZL29test_utf16le_with_replacementNSt3__14spanIKDsLm18446744073709551615EEE:
   27|  1.11k|static void test_utf16le_with_replacement(std::span<const char16_t> input) {
   28|  1.11k|  const auto implementations = get_supported_implementations();
   29|  1.11k|  if (implementations.empty()) {
  ------------------
  |  Branch (29:7): [True: 0, False: 1.11k]
  ------------------
   30|      0|    return;
   31|      0|  }
   32|       |
   33|       |  // Step 1: Collect length predictions from all implementations and check
   34|       |  // agreement.
   35|  1.11k|  std::vector<simdutf::result> len_results;
   36|  1.11k|  len_results.reserve(implementations.size());
   37|  3.33k|  for (auto impl : implementations) {
  ------------------
  |  Branch (37:18): [True: 3.33k, False: 1.11k]
  ------------------
   38|  3.33k|    len_results.push_back(impl->utf8_length_from_utf16le_with_replacement(
   39|  3.33k|        input.data(), input.size()));
   40|  3.33k|  }
   41|  1.11k|  {
   42|  1.11k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
   43|  1.11k|    if (std::ranges::adjacent_find(len_results, neq) != len_results.end()) {
  ------------------
  |  Branch (43:9): [True: 0, False: 1.11k]
  ------------------
   44|      0|      std::cerr << "utf8_length_from_utf16le_with_replacement: implementations "
   45|      0|                   "disagree\n";
   46|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (46:31): [True: 0, False: 0]
  ------------------
   47|      0|        std::cerr << "  " << implementations[i]->name()
   48|      0|                  << ": count=" << len_results[i].count
   49|      0|                  << " error=" << len_results[i].error << "\n";
   50|      0|      }
   51|      0|      std::abort();
   52|      0|    }
   53|  1.11k|  }
   54|       |
   55|  1.11k|  const std::size_t expected_len = len_results[0].count;
   56|       |  // error == SUCCESS means no surrogates encountered; SURROGATE means at least
   57|       |  // one.
   58|  1.11k|  const bool has_surrogates = (len_results[0].error != simdutf::SUCCESS);
   59|       |
   60|       |  // Step 2: Run conversion across all implementations and verify written ==
   61|       |  // expected_len.
   62|  1.11k|  std::vector<std::vector<char>> outputs;
   63|  1.11k|  outputs.reserve(implementations.size());
   64|  3.33k|  for (auto impl : implementations) {
  ------------------
  |  Branch (64:18): [True: 3.33k, False: 1.11k]
  ------------------
   65|  3.33k|    std::vector<char> out(expected_len);
   66|  3.33k|    const auto written = impl->convert_utf16le_to_utf8_with_replacement(
   67|  3.33k|        input.data(), input.size(), out.data());
   68|  3.33k|    if (written != expected_len) {
  ------------------
  |  Branch (68:9): [True: 0, False: 3.33k]
  ------------------
   69|      0|      std::cerr << "convert_utf16le_to_utf8_with_replacement:" << " written="
   70|      0|                << written << " but length predicted=" << expected_len
   71|      0|                << " impl=" << impl->name() << "\n";
   72|      0|      std::abort();
   73|      0|    }
   74|  3.33k|    outputs.push_back(std::move(out));
   75|  3.33k|  }
   76|       |
   77|       |  // Step 3: All implementations must agree on the output bytes.
   78|  1.11k|  {
   79|  1.11k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
   80|  1.11k|    if (std::ranges::adjacent_find(outputs, neq) != outputs.end()) {
  ------------------
  |  Branch (80:9): [True: 0, False: 1.11k]
  ------------------
   81|      0|      std::cerr << "convert_utf16le_to_utf8_with_replacement: outputs differ "
   82|      0|                   "between implementations\n";
   83|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (83:31): [True: 0, False: 0]
  ------------------
   84|      0|        std::cerr << "  " << implementations[i]->name()
   85|      0|                  << ": hash=" << FNV1A_hash::as_str(outputs[i]) << "\n";
   86|      0|      }
   87|      0|      std::abort();
   88|      0|    }
   89|  1.11k|  }
   90|       |
   91|       |  // Step 4: Output must always be valid UTF-8.
   92|  4.44k|  for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (92:27): [True: 3.33k, False: 1.11k]
  ------------------
   93|  3.33k|    if (!implementations[i]->validate_utf8(outputs[i].data(),
  ------------------
  |  Branch (93:9): [True: 0, False: 3.33k]
  ------------------
   94|  3.33k|                                           outputs[i].size())) {
   95|      0|      std::cerr << "convert_utf16le_to_utf8_with_replacement: output is not "
   96|      0|                   "valid UTF-8"
   97|      0|                << " impl=" << implementations[i]->name() << "\n";
   98|      0|      std::abort();
   99|      0|    }
  100|  3.33k|  }
  101|       |
  102|       |  // Step 5: When no surrogates were found, match the regular (non-replacement)
  103|       |  // length.
  104|  1.11k|  if (!has_surrogates) {
  ------------------
  |  Branch (104:7): [True: 374, False: 736]
  ------------------
  105|  1.49k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (105:29): [True: 1.12k, False: 374]
  ------------------
  106|  1.12k|      auto impl = implementations[i];
  107|  1.12k|      const auto regular_len =
  108|  1.12k|          impl->utf8_length_from_utf16le(input.data(), input.size());
  109|  1.12k|      if (regular_len != expected_len) {
  ------------------
  |  Branch (109:11): [True: 0, False: 1.12k]
  ------------------
  110|      0|        std::cerr
  111|      0|            << "utf16le_with_replacement: no surrogates but length mismatch:"
  112|      0|            << " with_replacement=" << expected_len
  113|      0|            << " regular=" << regular_len << " impl=" << impl->name() << "\n";
  114|      0|        std::abort();
  115|      0|      }
  116|  1.12k|    }
  117|    374|  }
  118|  1.11k|}
with_replacement.cpp:_ZZL29test_utf16le_with_replacementNSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clIN7simdutf6resultES6_EEDaRKT_RKT0_:
   42|  2.22k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
with_replacement.cpp:_ZZL29test_utf16le_with_replacementNSt3__14spanIKDsLm18446744073709551615EEEENK3$_1clINS_6vectorIcNS_9allocatorIcEEEES8_EEDaRKT_RKT0_:
   79|  2.22k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
with_replacement.cpp:_ZL29test_utf16be_with_replacementNSt3__14spanIKDsLm18446744073709551615EEE:
  120|  1.12k|static void test_utf16be_with_replacement(std::span<const char16_t> input) {
  121|  1.12k|  const auto implementations = get_supported_implementations();
  122|  1.12k|  if (implementations.empty()) {
  ------------------
  |  Branch (122:7): [True: 0, False: 1.12k]
  ------------------
  123|      0|    return;
  124|      0|  }
  125|       |
  126|       |  // Step 1: Collect length predictions from all implementations and check
  127|       |  // agreement.
  128|  1.12k|  std::vector<simdutf::result> len_results;
  129|  1.12k|  len_results.reserve(implementations.size());
  130|  3.37k|  for (auto impl : implementations) {
  ------------------
  |  Branch (130:18): [True: 3.37k, False: 1.12k]
  ------------------
  131|  3.37k|    len_results.push_back(impl->utf8_length_from_utf16be_with_replacement(
  132|  3.37k|        input.data(), input.size()));
  133|  3.37k|  }
  134|  1.12k|  {
  135|  1.12k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  136|  1.12k|    if (std::ranges::adjacent_find(len_results, neq) != len_results.end()) {
  ------------------
  |  Branch (136:9): [True: 0, False: 1.12k]
  ------------------
  137|      0|      std::cerr << "utf8_length_from_utf16be_with_replacement: implementations "
  138|      0|                   "disagree\n";
  139|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (139:31): [True: 0, False: 0]
  ------------------
  140|      0|        std::cerr << "  " << implementations[i]->name()
  141|      0|                  << ": count=" << len_results[i].count
  142|      0|                  << " error=" << len_results[i].error << "\n";
  143|      0|      }
  144|      0|      std::abort();
  145|      0|    }
  146|  1.12k|  }
  147|       |
  148|  1.12k|  const std::size_t expected_len = len_results[0].count;
  149|  1.12k|  const bool has_surrogates = (len_results[0].error != simdutf::SUCCESS);
  150|       |
  151|       |  // Step 2: Run conversion across all implementations and verify written ==
  152|       |  // expected_len.
  153|  1.12k|  std::vector<std::vector<char>> outputs;
  154|  1.12k|  outputs.reserve(implementations.size());
  155|  3.37k|  for (auto impl : implementations) {
  ------------------
  |  Branch (155:18): [True: 3.37k, False: 1.12k]
  ------------------
  156|  3.37k|    std::vector<char> out(expected_len);
  157|  3.37k|    const auto written = impl->convert_utf16be_to_utf8_with_replacement(
  158|  3.37k|        input.data(), input.size(), out.data());
  159|  3.37k|    if (written != expected_len) {
  ------------------
  |  Branch (159:9): [True: 0, False: 3.37k]
  ------------------
  160|      0|      std::cerr << "convert_utf16be_to_utf8_with_replacement:" << " written="
  161|      0|                << written << " but length predicted=" << expected_len
  162|      0|                << " impl=" << impl->name() << "\n";
  163|      0|      std::abort();
  164|      0|    }
  165|  3.37k|    outputs.push_back(std::move(out));
  166|  3.37k|  }
  167|       |
  168|       |  // Step 3: All implementations must agree on the output bytes.
  169|  1.12k|  {
  170|  1.12k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  171|  1.12k|    if (std::ranges::adjacent_find(outputs, neq) != outputs.end()) {
  ------------------
  |  Branch (171:9): [True: 0, False: 1.12k]
  ------------------
  172|      0|      std::cerr << "convert_utf16be_to_utf8_with_replacement: outputs differ "
  173|      0|                   "between implementations\n";
  174|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (174:31): [True: 0, False: 0]
  ------------------
  175|      0|        std::cerr << "  " << implementations[i]->name()
  176|      0|                  << ": hash=" << FNV1A_hash::as_str(outputs[i]) << "\n";
  177|      0|      }
  178|      0|      std::abort();
  179|      0|    }
  180|  1.12k|  }
  181|       |
  182|       |  // Step 4: Output must always be valid UTF-8.
  183|  4.49k|  for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (183:27): [True: 3.37k, False: 1.12k]
  ------------------
  184|  3.37k|    if (!implementations[i]->validate_utf8(outputs[i].data(),
  ------------------
  |  Branch (184:9): [True: 0, False: 3.37k]
  ------------------
  185|  3.37k|                                           outputs[i].size())) {
  186|      0|      std::cerr << "convert_utf16be_to_utf8_with_replacement: output is not "
  187|      0|                   "valid UTF-8"
  188|      0|                << " impl=" << implementations[i]->name() << "\n";
  189|      0|      std::abort();
  190|      0|    }
  191|  3.37k|  }
  192|       |
  193|       |  // Step 5: When no surrogates were found, match the regular (non-replacement)
  194|       |  // length.
  195|  1.12k|  if (!has_surrogates) {
  ------------------
  |  Branch (195:7): [True: 389, False: 735]
  ------------------
  196|  1.55k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (196:29): [True: 1.16k, False: 389]
  ------------------
  197|  1.16k|      auto impl = implementations[i];
  198|  1.16k|      const auto regular_len =
  199|  1.16k|          impl->utf8_length_from_utf16be(input.data(), input.size());
  200|  1.16k|      if (regular_len != expected_len) {
  ------------------
  |  Branch (200:11): [True: 0, False: 1.16k]
  ------------------
  201|      0|        std::cerr
  202|      0|            << "utf16be_with_replacement: no surrogates but length mismatch:"
  203|      0|            << " with_replacement=" << expected_len
  204|      0|            << " regular=" << regular_len << " impl=" << impl->name() << "\n";
  205|      0|        std::abort();
  206|      0|      }
  207|  1.16k|    }
  208|    389|  }
  209|  1.12k|}
with_replacement.cpp:_ZZL29test_utf16be_with_replacementNSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clIN7simdutf6resultES6_EEDaRKT_RKT0_:
  135|  2.24k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
with_replacement.cpp:_ZZL29test_utf16be_with_replacementNSt3__14spanIKDsLm18446744073709551615EEEENK3$_1clINS_6vectorIcNS_9allocatorIcEEEES8_EEDaRKT_RKT0_:
  170|  2.24k|    auto neq = [](const auto& a, const auto& b) { return a != b; };

_ZN7simdutf6resultC2ENS_10error_codeEm:
   87|  9.72k|      : error{err}, count{pos} {}

_ZNK7simdutf14implementation4nameEv:
 5092|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5143|      8|  virtual uint32_t required_instruction_sets() const {
 5144|      8|    return _required_instruction_sets;
 5145|      8|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7029|      4|      : _name(name), _description(description),
 7030|      4|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7061|      1|  simdutf_really_inline available_implementation_list() {}

simdutf.cpp:_ZN7simdutf8internalL30detect_supported_architecturesEv:
  236|      8|static inline uint32_t detect_supported_architectures() {
  237|      8|  uint32_t eax;
  238|      8|  uint32_t ebx = 0;
  239|      8|  uint32_t ecx = 0;
  240|      8|  uint32_t edx = 0;
  241|      8|  uint32_t host_isa = 0x0;
  242|       |
  243|       |  // EBX for EAX=0x1
  244|      8|  eax = 0x1;
  245|      8|  cpuid(&eax, &ebx, &ecx, &edx);
  246|       |
  247|      8|  if (ecx & cpuid_bit::sse42) {
  ------------------
  |  Branch (247:7): [True: 8, False: 0]
  ------------------
  248|      8|    host_isa |= instruction_set::SSE42;
  249|      8|  }
  250|       |
  251|      8|  if (ecx & cpuid_bit::pclmulqdq) {
  ------------------
  |  Branch (251:7): [True: 8, False: 0]
  ------------------
  252|      8|    host_isa |= instruction_set::PCLMULQDQ;
  253|      8|  }
  254|       |
  255|      8|  if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) {
  ------------------
  |  Branch (255:7): [True: 0, False: 8]
  ------------------
  256|      0|    return host_isa;
  257|      0|  }
  258|       |
  259|       |  // xgetbv for checking if the OS saves registers
  260|      8|  uint64_t xcr0 = xgetbv();
  261|       |
  262|      8|  if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) {
  ------------------
  |  Branch (262:7): [True: 0, False: 8]
  ------------------
  263|      0|    return host_isa;
  264|      0|  }
  265|       |  // ECX for EAX=0x7
  266|      8|  eax = 0x7;
  267|      8|  ecx = 0x0; // Sub-leaf = 0
  268|      8|  cpuid(&eax, &ebx, &ecx, &edx);
  269|      8|  if (ebx & cpuid_bit::ebx::avx2) {
  ------------------
  |  Branch (269:7): [True: 8, False: 0]
  ------------------
  270|      8|    host_isa |= instruction_set::AVX2;
  271|      8|  }
  272|      8|  if (ebx & cpuid_bit::ebx::bmi1) {
  ------------------
  |  Branch (272:7): [True: 8, False: 0]
  ------------------
  273|      8|    host_isa |= instruction_set::BMI1;
  274|      8|  }
  275|      8|  if (ebx & cpuid_bit::ebx::bmi2) {
  ------------------
  |  Branch (275:7): [True: 8, False: 0]
  ------------------
  276|      8|    host_isa |= instruction_set::BMI2;
  277|      8|  }
  278|      8|  if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) ==
  ------------------
  |  Branch (278:7): [True: 8, False: 0]
  ------------------
  279|      8|        cpuid_bit::xcr0_bit::avx512_saved)) {
  280|      8|    return host_isa;
  281|      8|  }
  282|      0|  if (ebx & cpuid_bit::ebx::avx512f) {
  ------------------
  |  Branch (282:7): [True: 0, False: 0]
  ------------------
  283|      0|    host_isa |= instruction_set::AVX512F;
  284|      0|  }
  285|      0|  if (ebx & cpuid_bit::ebx::avx512bw) {
  ------------------
  |  Branch (285:7): [True: 0, False: 0]
  ------------------
  286|      0|    host_isa |= instruction_set::AVX512BW;
  287|      0|  }
  288|      0|  if (ebx & cpuid_bit::ebx::avx512cd) {
  ------------------
  |  Branch (288:7): [True: 0, False: 0]
  ------------------
  289|      0|    host_isa |= instruction_set::AVX512CD;
  290|      0|  }
  291|      0|  if (ebx & cpuid_bit::ebx::avx512dq) {
  ------------------
  |  Branch (291:7): [True: 0, False: 0]
  ------------------
  292|      0|    host_isa |= instruction_set::AVX512DQ;
  293|      0|  }
  294|      0|  if (ebx & cpuid_bit::ebx::avx512vl) {
  ------------------
  |  Branch (294:7): [True: 0, False: 0]
  ------------------
  295|      0|    host_isa |= instruction_set::AVX512VL;
  296|      0|  }
  297|      0|  if (ecx & cpuid_bit::ecx::avx512vbmi2) {
  ------------------
  |  Branch (297:7): [True: 0, False: 0]
  ------------------
  298|      0|    host_isa |= instruction_set::AVX512VBMI2;
  299|      0|  }
  300|      0|  if (ecx & cpuid_bit::ecx::avx512vpopcnt) {
  ------------------
  |  Branch (300:7): [True: 0, False: 0]
  ------------------
  301|      0|    host_isa |= instruction_set::AVX512VPOPCNTDQ;
  302|      0|  }
  303|      0|  return host_isa;
  304|      8|}
simdutf.cpp:_ZN7simdutf8internalL5cpuidEPjS1_S1_S1_:
  202|     16|                         uint32_t *edx) {
  203|       |  #if defined(_MSC_VER)
  204|       |  int cpu_info[4];
  205|       |  __cpuidex(cpu_info, *eax, *ecx);
  206|       |  *eax = cpu_info[0];
  207|       |  *ebx = cpu_info[1];
  208|       |  *ecx = cpu_info[2];
  209|       |  *edx = cpu_info[3];
  210|       |  #elif (defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)) ||         \
  211|       |      defined(__FILC__)
  212|       |  uint32_t level = *eax;
  213|       |  __get_cpuid(level, eax, ebx, ecx, edx);
  214|       |  #else
  215|     16|  uint32_t a = *eax, b, c = *ecx, d;
  216|     16|  asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d));
  217|     16|  *eax = a;
  218|     16|  *ebx = b;
  219|     16|  *ecx = c;
  220|     16|  *edx = d;
  221|     16|  #endif
  222|     16|}
simdutf.cpp:_ZN7simdutf8internalL6xgetbvEv:
  224|      8|static inline uint64_t xgetbv() {
  225|       |  #if defined(_MSC_VER)
  226|       |  return _xgetbv(0);
  227|       |  #elif defined(__FILC__)
  228|       |  return zxgetbv();
  229|       |  #else
  230|      8|  uint32_t xcr0_lo, xcr0_hi;
  231|      8|  asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0));
  232|      8|  return xcr0_lo | ((uint64_t)xcr0_hi << 32);
  233|      8|  #endif
  234|      8|}

_ZN7simdutf6scalar14u16_swap_bytesEt:
    8|   140M|u16_swap_bytes(const uint16_t word) {
    9|   140M|  return uint16_t((word >> 8) | (word << 8));
   10|   140M|}
_ZN7simdutf6scalar5utf1614swap_if_neededILNS_10endiannessE1EEEtt:
   27|  54.3M|template <endianness big_endian> constexpr uint16_t swap_if_needed(uint16_t c) {
   28|  54.3M|  return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c;
  ------------------
  |  Branch (28:10): [True: 54.3M, Folded]
  ------------------
   29|  54.3M|}
_ZN7simdutf6scalar5utf1614swap_if_neededILNS_10endiannessE0EEEtt:
   27|  64.4M|template <endianness big_endian> constexpr uint16_t swap_if_needed(uint16_t c) {
   28|  64.4M|  return !match_system(big_endian) ? scalar::u16_swap_bytes(c) : c;
  ------------------
  |  Branch (28:10): [Folded, False: 64.4M]
  ------------------
   29|  64.4M|}

_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  25.1M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  25.1M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  25.1M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 2.03M, False: 23.1M]
  |  Branch (139:26): [True: 575k, False: 1.45M]
  ------------------
  140|  25.1M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  29.3M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  29.3M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  29.3M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 1.85M, False: 27.5M]
  |  Branch (144:26): [True: 519k, False: 1.33M]
  ------------------
  145|  29.3M|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  21.2M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  21.2M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  21.2M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 1.72M, False: 19.5M]
  |  Branch (139:26): [True: 465k, False: 1.25M]
  ------------------
  140|  21.2M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  24.9M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  24.9M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  24.9M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 1.56M, False: 23.3M]
  |  Branch (144:26): [True: 294k, False: 1.26M]
  ------------------
  145|  24.9M|}
_ZN7simdutf6scalar5utf1622utf8_length_from_utf16ILNS_10endiannessE0EEEmPKDsm:
   91|  1.12k|                                                  size_t len) {
   92|       |  // We are not BOM aware.
   93|  1.12k|  size_t counter{0};
   94|  9.92M|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (94:22): [True: 9.92M, False: 1.12k]
  ------------------
   95|  9.92M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]);
   96|  9.92M|    counter++; // ASCII
   97|  9.92M|    counter += static_cast<size_t>(
   98|  9.92M|        word >
   99|  9.92M|        0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes
  100|  9.92M|    counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) ||
  ------------------
  |  Branch (100:37): [True: 5.54M, False: 4.37M]
  |  Branch (100:53): [True: 5.47M, False: 75.4k]
  ------------------
  101|  4.45M|                                   (word >= 0xE000)); // three-byte
  ------------------
  |  Branch (101:36): [True: 75.4k, False: 4.37M]
  ------------------
  102|  9.92M|  }
  103|  1.12k|  return counter;
  104|  1.12k|}
_ZN7simdutf6scalar5utf1622utf8_length_from_utf16ILNS_10endiannessE1EEEmPKDsm:
   91|  1.16k|                                                  size_t len) {
   92|       |  // We are not BOM aware.
   93|  1.16k|  size_t counter{0};
   94|  8.12M|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (94:22): [True: 8.12M, False: 1.16k]
  ------------------
   95|  8.12M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(p[i]);
   96|  8.12M|    counter++; // ASCII
   97|  8.12M|    counter += static_cast<size_t>(
   98|  8.12M|        word >
   99|  8.12M|        0x7F); // non-ASCII is at least 2 bytes, surrogates are 2*2 == 4 bytes
  100|  8.12M|    counter += static_cast<size_t>((word > 0x7FF && word <= 0xD7FF) ||
  ------------------
  |  Branch (100:37): [True: 4.36M, False: 3.75M]
  |  Branch (100:53): [True: 4.06M, False: 299k]
  ------------------
  101|  4.05M|                                   (word >= 0xE000)); // three-byte
  ------------------
  |  Branch (101:36): [True: 299k, False: 3.75M]
  ------------------
  102|  8.12M|  }
  103|  1.16k|  return counter;
  104|  1.16k|}
_ZN7simdutf6scalar5utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE0EEENS_6resultEPKDsm:
  153|  3.33k|utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) {
  154|  3.33k|  bool any_surrogates = false;
  155|       |  // We are not BOM aware.
  156|  3.33k|  size_t counter{0};
  157|  25.1M|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (157:22): [True: 25.1M, False: 3.33k]
  ------------------
  158|  25.1M|    if (is_high_surrogate<big_endian>(p[i])) {
  ------------------
  |  Branch (158:9): [True: 574k, False: 24.5M]
  ------------------
  159|   574k|      any_surrogates = true;
  160|       |      // surrogate pair
  161|   574k|      if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) {
  ------------------
  |  Branch (161:11): [True: 574k, False: 492]
  |  Branch (161:26): [True: 151k, False: 422k]
  ------------------
  162|   151k|        counter += 4;
  163|   151k|        i++; // skip low surrogate
  164|   423k|      } else {
  165|   423k|        counter += 3; // unpaired high surrogate replaced by U+FFFD
  166|   423k|      }
  167|   574k|      continue;
  168|  24.5M|    } else if (is_low_surrogate<big_endian>(p[i])) {
  ------------------
  |  Branch (168:16): [True: 356k, False: 24.2M]
  ------------------
  169|   356k|      any_surrogates = true;
  170|   356k|      counter += 3; // unpaired low surrogate replaced by U+FFFD
  171|   356k|      continue;
  172|   356k|    }
  173|  24.2M|    char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i];
  ------------------
  |  Branch (173:21): [Folded, False: 24.2M]
  ------------------
  174|  24.2M|    counter++; // at least 1 byte
  175|  24.2M|    counter +=
  176|  24.2M|        static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes
  177|  24.2M|    counter += static_cast<size_t>(word > 0x7FF); // three-byte
  178|  24.2M|  }
  179|  3.33k|  return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS,
  ------------------
  |  Branch (179:11): [True: 1.68k, False: 1.64k]
  ------------------
  180|  3.33k|          counter};
  181|  3.33k|}
_ZN7simdutf6scalar5utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE1EEENS_6resultEPKDsm:
  153|  3.37k|utf8_length_from_utf16_with_replacement(const char16_t *p, size_t len) {
  154|  3.37k|  bool any_surrogates = false;
  155|       |  // We are not BOM aware.
  156|  3.37k|  size_t counter{0};
  157|  21.2M|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (157:22): [True: 21.2M, False: 3.37k]
  ------------------
  158|  21.2M|    if (is_high_surrogate<big_endian>(p[i])) {
  ------------------
  |  Branch (158:9): [True: 465k, False: 20.8M]
  ------------------
  159|   465k|      any_surrogates = true;
  160|       |      // surrogate pair
  161|   465k|      if (i + 1 < len && is_low_surrogate<big_endian>(p[i + 1])) {
  ------------------
  |  Branch (161:11): [True: 464k, False: 450]
  |  Branch (161:26): [True: 87.3k, False: 377k]
  ------------------
  162|  87.3k|        counter += 4;
  163|  87.3k|        i++; // skip low surrogate
  164|   377k|      } else {
  165|   377k|        counter += 3; // unpaired high surrogate replaced by U+FFFD
  166|   377k|      }
  167|   465k|      continue;
  168|  20.8M|    } else if (is_low_surrogate<big_endian>(p[i])) {
  ------------------
  |  Branch (168:16): [True: 199k, False: 20.6M]
  ------------------
  169|   199k|      any_surrogates = true;
  170|   199k|      counter += 3; // unpaired low surrogate replaced by U+FFFD
  171|   199k|      continue;
  172|   199k|    }
  173|  20.6M|    char16_t word = !match_system(big_endian) ? u16_swap_bytes(p[i]) : p[i];
  ------------------
  |  Branch (173:21): [True: 20.6M, Folded]
  ------------------
  174|  20.6M|    counter++; // at least 1 byte
  175|  20.6M|    counter +=
  176|  20.6M|        static_cast<size_t>(word > 0x7F); // non-ASCII is at least 2 bytes
  177|  20.6M|    counter += static_cast<size_t>(word > 0x7FF); // three-byte
  178|  20.6M|  }
  179|  3.37k|  return {any_surrogates ? error_code::SURROGATE : error_code::SUCCESS,
  ------------------
  |  Branch (179:11): [True: 1.65k, False: 1.71k]
  ------------------
  180|  3.37k|          counter};
  181|  3.37k|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_113utf16_to_utf824convert_with_replacementILNS_10endiannessE0EEEmPKDsmPc:
  212|  3.33k|                                                    char *utf8_output) {
  213|  3.33k|  size_t pos = 0;
  214|  3.33k|  char *start = utf8_output;
  215|  58.9M|  while (pos < len) {
  ------------------
  |  Branch (215:10): [True: 58.9M, False: 3.33k]
  ------------------
  216|       |#if SIMDUTF_CPLUSPLUS23
  217|       |    if !consteval
  218|       |#endif
  219|  58.9M|    {
  220|       |      // try to convert the next block of 8 bytes
  221|  58.9M|      if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that
  ------------------
  |  Branch (221:11): [True: 58.9M, False: 8.27k]
  ------------------
  222|       |                            // they are ascii
  223|  58.9M|        uint64_t v;
  224|  58.9M|        ::memcpy(&v, data + pos, sizeof(uint64_t));
  225|       |        if constexpr (!match_system(big_endian)) {
  226|       |          v = (v >> 8) | (v << (64 - 8));
  227|       |        }
  228|  58.9M|        if ((v & 0xFF80FF80FF80FF80) == 0) {
  ------------------
  |  Branch (228:13): [True: 5.48M, False: 53.4M]
  ------------------
  229|  5.48M|          size_t final_pos = pos + 4;
  230|  27.4M|          while (pos < final_pos) {
  ------------------
  |  Branch (230:18): [True: 21.9M, False: 5.48M]
  ------------------
  231|  21.9M|            *utf8_output++ = !match_system(big_endian)
  ------------------
  |  Branch (231:30): [Folded, False: 21.9M]
  ------------------
  232|  21.9M|                                 ? char(u16_swap_bytes(data[pos]))
  233|  21.9M|                                 : char(data[pos]);
  234|  21.9M|            pos++;
  235|  21.9M|          }
  236|  5.48M|          continue;
  237|  5.48M|        }
  238|  58.9M|      }
  239|  58.9M|    }
  240|  53.4M|    uint16_t word =
  241|  53.4M|        !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos];
  ------------------
  |  Branch (241:9): [Folded, False: 53.4M]
  ------------------
  242|  53.4M|    if ((word & 0xFF80) == 0) {
  ------------------
  |  Branch (242:9): [True: 1.73M, False: 51.7M]
  ------------------
  243|       |      // will generate one UTF-8 bytes
  244|  1.73M|      *utf8_output++ = char(word);
  245|  1.73M|      pos++;
  246|  51.7M|    } else if ((word & 0xF800) == 0) {
  ------------------
  |  Branch (246:16): [True: 1.62M, False: 50.1M]
  ------------------
  247|       |      // will generate two UTF-8 bytes
  248|       |      // we have 0b110XXXXX 0b10XXXXXX
  249|  1.62M|      *utf8_output++ = char((word >> 6) | 0b11000000);
  250|  1.62M|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  251|  1.62M|      pos++;
  252|  50.1M|    } else if ((word & 0xF800) != 0xD800) {
  ------------------
  |  Branch (252:16): [True: 47.3M, False: 2.78M]
  ------------------
  253|       |      // will generate three UTF-8 bytes
  254|       |      // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
  255|  47.3M|      *utf8_output++ = char((word >> 12) | 0b11100000);
  256|  47.3M|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  257|  47.3M|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  258|  47.3M|      pos++;
  259|  47.3M|    } else {
  260|       |      // surrogate range
  261|  2.78M|      uint16_t diff = uint16_t(word - 0xD800);
  262|  2.78M|      if (diff <= 0x3FF && pos + 1 < len) {
  ------------------
  |  Branch (262:11): [True: 1.72M, False: 1.06M]
  |  Branch (262:28): [True: 1.71M, False: 492]
  ------------------
  263|       |        // high surrogate, check for valid pair
  264|  1.71M|        uint16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (264:30): [Folded, False: 1.71M]
  ------------------
  265|  1.71M|                                 ? u16_swap_bytes(data[pos + 1])
  266|  1.71M|                                 : data[pos + 1];
  267|  1.71M|        uint16_t diff2 = uint16_t(next_word - 0xDC00);
  268|  1.71M|        if (diff2 <= 0x3FF) {
  ------------------
  |  Branch (268:13): [True: 454k, False: 1.26M]
  ------------------
  269|       |          // valid surrogate pair
  270|   454k|          uint32_t value = (diff << 10) + diff2 + 0x10000;
  271|       |          // will generate four UTF-8 bytes
  272|   454k|          *utf8_output++ = char((value >> 18) | 0b11110000);
  273|   454k|          *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000);
  274|   454k|          *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000);
  275|   454k|          *utf8_output++ = char((value & 0b111111) | 0b10000000);
  276|   454k|          pos += 2;
  277|   454k|          continue;
  278|   454k|        }
  279|  1.71M|      }
  280|       |      // unpaired surrogate: replace with U+FFFD (0xEF 0xBF 0xBD)
  281|  2.33M|      *utf8_output++ = char(0xef);
  282|  2.33M|      *utf8_output++ = char(0xbf);
  283|  2.33M|      *utf8_output++ = char(0xbd);
  284|  2.33M|      pos++;
  285|  2.33M|    }
  286|  53.4M|  }
  287|  3.33k|  return utf8_output - start;
  288|  3.33k|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_113utf16_to_utf824convert_with_replacementILNS_10endiannessE1EEEmPKDsmPc:
  212|  3.37k|                                                    char *utf8_output) {
  213|  3.37k|  size_t pos = 0;
  214|  3.37k|  char *start = utf8_output;
  215|  45.6M|  while (pos < len) {
  ------------------
  |  Branch (215:10): [True: 45.6M, False: 3.37k]
  ------------------
  216|       |#if SIMDUTF_CPLUSPLUS23
  217|       |    if !consteval
  218|       |#endif
  219|  45.6M|    {
  220|       |      // try to convert the next block of 8 bytes
  221|  45.6M|      if (pos + 4 <= len) { // if it is safe to read 8 more bytes, check that
  ------------------
  |  Branch (221:11): [True: 45.6M, False: 8.25k]
  ------------------
  222|       |                            // they are ascii
  223|  45.6M|        uint64_t v;
  224|  45.6M|        ::memcpy(&v, data + pos, sizeof(uint64_t));
  225|  45.6M|        if constexpr (!match_system(big_endian)) {
  226|  45.6M|          v = (v >> 8) | (v << (64 - 8));
  227|  45.6M|        }
  228|  45.6M|        if ((v & 0xFF80FF80FF80FF80) == 0) {
  ------------------
  |  Branch (228:13): [True: 6.04M, False: 39.6M]
  ------------------
  229|  6.04M|          size_t final_pos = pos + 4;
  230|  30.2M|          while (pos < final_pos) {
  ------------------
  |  Branch (230:18): [True: 24.1M, False: 6.04M]
  ------------------
  231|  24.1M|            *utf8_output++ = !match_system(big_endian)
  ------------------
  |  Branch (231:30): [True: 24.1M, Folded]
  ------------------
  232|  24.1M|                                 ? char(u16_swap_bytes(data[pos]))
  233|  24.1M|                                 : char(data[pos]);
  234|  24.1M|            pos++;
  235|  24.1M|          }
  236|  6.04M|          continue;
  237|  6.04M|        }
  238|  45.6M|      }
  239|  45.6M|    }
  240|  39.6M|    uint16_t word =
  241|  39.6M|        !match_system(big_endian) ? u16_swap_bytes(data[pos]) : data[pos];
  ------------------
  |  Branch (241:9): [True: 39.6M, Folded]
  ------------------
  242|  39.6M|    if ((word & 0xFF80) == 0) {
  ------------------
  |  Branch (242:9): [True: 730k, False: 38.8M]
  ------------------
  243|       |      // will generate one UTF-8 bytes
  244|   730k|      *utf8_output++ = char(word);
  245|   730k|      pos++;
  246|  38.8M|    } else if ((word & 0xF800) == 0) {
  ------------------
  |  Branch (246:16): [True: 1.00M, False: 37.8M]
  ------------------
  247|       |      // will generate two UTF-8 bytes
  248|       |      // we have 0b110XXXXX 0b10XXXXXX
  249|  1.00M|      *utf8_output++ = char((word >> 6) | 0b11000000);
  250|  1.00M|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  251|  1.00M|      pos++;
  252|  37.8M|    } else if ((word & 0xF800) != 0xD800) {
  ------------------
  |  Branch (252:16): [True: 35.8M, False: 1.98M]
  ------------------
  253|       |      // will generate three UTF-8 bytes
  254|       |      // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
  255|  35.8M|      *utf8_output++ = char((word >> 12) | 0b11100000);
  256|  35.8M|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  257|  35.8M|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  258|  35.8M|      pos++;
  259|  35.8M|    } else {
  260|       |      // surrogate range
  261|  1.98M|      uint16_t diff = uint16_t(word - 0xD800);
  262|  1.98M|      if (diff <= 0x3FF && pos + 1 < len) {
  ------------------
  |  Branch (262:11): [True: 1.39M, False: 596k]
  |  Branch (262:28): [True: 1.38M, False: 450]
  ------------------
  263|       |        // high surrogate, check for valid pair
  264|  1.38M|        uint16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (264:30): [True: 1.38M, Folded]
  ------------------
  265|  1.38M|                                 ? u16_swap_bytes(data[pos + 1])
  266|  1.38M|                                 : data[pos + 1];
  267|  1.38M|        uint16_t diff2 = uint16_t(next_word - 0xDC00);
  268|  1.38M|        if (diff2 <= 0x3FF) {
  ------------------
  |  Branch (268:13): [True: 260k, False: 1.12M]
  ------------------
  269|       |          // valid surrogate pair
  270|   260k|          uint32_t value = (diff << 10) + diff2 + 0x10000;
  271|       |          // will generate four UTF-8 bytes
  272|   260k|          *utf8_output++ = char((value >> 18) | 0b11110000);
  273|   260k|          *utf8_output++ = char(((value >> 12) & 0b111111) | 0b10000000);
  274|   260k|          *utf8_output++ = char(((value >> 6) & 0b111111) | 0b10000000);
  275|   260k|          *utf8_output++ = char((value & 0b111111) | 0b10000000);
  276|   260k|          pos += 2;
  277|   260k|          continue;
  278|   260k|        }
  279|  1.38M|      }
  280|       |      // unpaired surrogate: replace with U+FFFD (0xEF 0xBF 0xBD)
  281|  1.72M|      *utf8_output++ = char(0xef);
  282|  1.72M|      *utf8_output++ = char(0xbf);
  283|  1.72M|      *utf8_output++ = char(0xbd);
  284|  1.72M|      pos++;
  285|  1.72M|    }
  286|  39.6M|  }
  287|  3.37k|  return utf8_output - start;
  288|  3.37k|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_14utf88validateEPKcm:
  111|  2.23k|                                                        size_t len) noexcept {
  112|  2.23k|  return validate(reinterpret_cast<const uint8_t *>(buf), len);
  113|  2.23k|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_14utf88validateIPKhEEbT_m:
   12|  2.23k|                                                      size_t len) noexcept {
   13|  2.23k|  static_assert(
   14|  2.23k|      std::is_same<typename std::decay<decltype(*data)>::type, uint8_t>::value,
   15|  2.23k|      "dereferencing the data pointer must result in a uint8_t");
   16|  2.23k|  uint64_t pos = 0;
   17|  2.23k|  uint32_t code_point = 0;
   18|  31.1M|  while (pos < len) {
  ------------------
  |  Branch (18:10): [True: 31.1M, False: 1.97k]
  ------------------
   19|  31.1M|    uint64_t next_pos;
   20|       |#if SIMDUTF_CPLUSPLUS23
   21|       |    if !consteval
   22|       |#endif
   23|  31.1M|    { // check if the next 16 bytes are ascii.
   24|  31.1M|      next_pos = pos + 16;
   25|  31.1M|      if (next_pos <= len) { // if it is safe to read 16 more bytes, check
  ------------------
  |  Branch (25:11): [True: 31.1M, False: 8.49k]
  ------------------
   26|       |                             // that they are ascii
   27|  31.1M|        uint64_t v1{};
   28|  31.1M|        std::memcpy(&v1, data + pos, sizeof(uint64_t));
   29|  31.1M|        uint64_t v2{};
   30|  31.1M|        std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   31|  31.1M|        uint64_t v{v1 | v2};
   32|  31.1M|        if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (32:13): [True: 918k, False: 30.1M]
  ------------------
   33|   918k|          pos = next_pos;
   34|   918k|          continue;
   35|   918k|        }
   36|  31.1M|      }
   37|  31.1M|    }
   38|       |
   39|  30.2M|    unsigned char byte = data[pos];
   40|       |
   41|  31.7M|    while (byte < 0b10000000) {
  ------------------
  |  Branch (41:12): [True: 1.50M, False: 30.2M]
  ------------------
   42|  1.50M|      if (++pos == len) {
  ------------------
  |  Branch (42:11): [True: 264, False: 1.50M]
  ------------------
   43|    264|        return true;
   44|    264|      }
   45|  1.50M|      byte = data[pos];
   46|  1.50M|    }
   47|       |
   48|  30.2M|    if ((byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (48:9): [True: 877k, False: 29.3M]
  ------------------
   49|   877k|      next_pos = pos + 2;
   50|   877k|      if (next_pos > len) {
  ------------------
  |  Branch (50:11): [True: 0, False: 877k]
  ------------------
   51|      0|        return false;
   52|      0|      }
   53|   877k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (53:11): [True: 0, False: 877k]
  ------------------
   54|      0|        return false;
   55|      0|      }
   56|       |      // range check
   57|   877k|      code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
   58|   877k|      if (code_point < 0x80) {
  ------------------
  |  Branch (58:11): [True: 0, False: 877k]
  ------------------
   59|      0|        return false;
   60|      0|      }
   61|  29.3M|    } else if ((byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (61:16): [True: 29.0M, False: 238k]
  ------------------
   62|  29.0M|      next_pos = pos + 3;
   63|  29.0M|      if (next_pos > len) {
  ------------------
  |  Branch (63:11): [True: 0, False: 29.0M]
  ------------------
   64|      0|        return false;
   65|      0|      }
   66|  29.0M|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (66:11): [True: 0, False: 29.0M]
  ------------------
   67|      0|        return false;
   68|      0|      }
   69|  29.0M|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (69:11): [True: 0, False: 29.0M]
  ------------------
   70|      0|        return false;
   71|      0|      }
   72|       |      // range check
   73|  29.0M|      code_point = (byte & 0b00001111) << 12 |
   74|  29.0M|                   (data[pos + 1] & 0b00111111) << 6 |
   75|  29.0M|                   (data[pos + 2] & 0b00111111);
   76|  29.0M|      if ((code_point < 0x800) ||
  ------------------
  |  Branch (76:11): [True: 0, False: 29.0M]
  ------------------
   77|  29.0M|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (77:12): [True: 3.50M, False: 25.5M]
  |  Branch (77:35): [True: 0, False: 3.50M]
  ------------------
   78|      0|        return false;
   79|      0|      }
   80|  29.0M|    } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000
  ------------------
  |  Branch (80:16): [True: 238k, False: 0]
  ------------------
   81|   238k|      next_pos = pos + 4;
   82|   238k|      if (next_pos > len) {
  ------------------
  |  Branch (82:11): [True: 0, False: 238k]
  ------------------
   83|      0|        return false;
   84|      0|      }
   85|   238k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (85:11): [True: 0, False: 238k]
  ------------------
   86|      0|        return false;
   87|      0|      }
   88|   238k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (88:11): [True: 0, False: 238k]
  ------------------
   89|      0|        return false;
   90|      0|      }
   91|   238k|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (91:11): [True: 0, False: 238k]
  ------------------
   92|      0|        return false;
   93|      0|      }
   94|       |      // range check
   95|   238k|      code_point =
   96|   238k|          (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 |
   97|   238k|          (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111);
   98|   238k|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (98:11): [True: 0, False: 238k]
  |  Branch (98:35): [True: 0, False: 238k]
  ------------------
   99|      0|        return false;
  100|      0|      }
  101|   238k|    } else {
  102|       |      // we may have a continuation
  103|      0|      return false;
  104|      0|    }
  105|  30.2M|    pos = next_pos;
  106|  30.2M|  }
  107|  1.97k|  return true;
  108|  2.23k|}

_ZNK7simdutf8fallback14implementation13validate_utf8EPKcm:
   37|  2.23k|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
   38|  2.23k|  return scalar::utf8::validate(buf, len);
   39|  2.23k|}
_ZNK7simdutf8fallback14implementation24utf8_length_from_utf16leEPKDsm:
  452|    374|    const char16_t *input, size_t length) const noexcept {
  453|    374|  return scalar::utf16::utf8_length_from_utf16<endianness::LITTLE>(input,
  454|    374|                                                                   length);
  455|    374|}
_ZNK7simdutf8fallback14implementation24utf8_length_from_utf16beEPKDsm:
  458|    389|    const char16_t *input, size_t length) const noexcept {
  459|    389|  return scalar::utf16::utf8_length_from_utf16<endianness::BIG>(input, length);
  460|    389|}
_ZNK7simdutf8fallback14implementation41utf8_length_from_utf16le_with_replacementEPKDsm:
  483|  1.11k|    const char16_t *input, size_t length) const noexcept {
  484|  1.11k|  return scalar::utf16::utf8_length_from_utf16_with_replacement<
  485|  1.11k|      endianness::LITTLE>(input, length);
  486|  1.11k|}
_ZNK7simdutf8fallback14implementation41utf8_length_from_utf16be_with_replacementEPKDsm:
  490|  1.12k|    const char16_t *input, size_t length) const noexcept {
  491|  1.12k|  return scalar::utf16::utf8_length_from_utf16_with_replacement<
  492|  1.12k|      endianness::BIG>(input, length);
  493|  1.12k|}
_ZNK7simdutf8fallback14implementation40convert_utf16le_to_utf8_with_replacementEPKDsmPc:
  497|  1.11k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
  498|  1.11k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::LITTLE>(
  499|  1.11k|      input, length, utf8_buffer);
  500|  1.11k|}
_ZNK7simdutf8fallback14implementation40convert_utf16be_to_utf8_with_replacementEPKDsmPc:
  504|  1.12k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
  505|  1.12k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::BIG>(
  506|  1.12k|      input, length, utf8_buffer);
  507|  1.12k|}

simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_116buf_block_readerILm64EE13get_remainderEPh:
   57|  2.23k|buf_block_reader<STEP_SIZE>::get_remainder(uint8_t *dst) const {
   58|  2.23k|  if (len == idx) {
  ------------------
  |  Branch (58:7): [True: 4, False: 2.23k]
  ------------------
   59|      4|    return 0;
   60|      4|  } // memcpy(dst, null, 0) will trigger an error with some sanitizers
   61|  2.23k|  std::memset(dst, 0x20,
   62|  2.23k|              STEP_SIZE); // std::memset STEP_SIZE because it is more efficient
   63|       |                          // to write out 8 or 16 bytes at once.
   64|  2.23k|  std::memcpy(dst, buf + idx, len - idx);
   65|  2.23k|  return len - idx;
   66|  2.23k|}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_116buf_block_readerILm64EE13get_remainderEPh:
   57|  2.23k|buf_block_reader<STEP_SIZE>::get_remainder(uint8_t *dst) const {
   58|  2.23k|  if (len == idx) {
  ------------------
  |  Branch (58:7): [True: 4, False: 2.23k]
  ------------------
   59|      4|    return 0;
   60|      4|  } // memcpy(dst, null, 0) will trigger an error with some sanitizers
   61|  2.23k|  std::memset(dst, 0x20,
   62|  2.23k|              STEP_SIZE); // std::memset STEP_SIZE because it is more efficient
   63|       |                          // to write out 8 or 16 bytes at once.
   64|  2.23k|  std::memcpy(dst, buf + idx, len - idx);
   65|  2.23k|  return len - idx;
   66|  2.23k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116buf_block_readerILm64EEC2EPKhm:
   36|  2.23k|    : buf{_buf}, len{_len}, lenminusstep{len < STEP_SIZE ? 0 : len - STEP_SIZE},
  ------------------
  |  Branch (36:42): [True: 1.53k, False: 703]
  ------------------
   37|  2.23k|      idx{0} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_116buf_block_readerILm64EE14has_full_blockEv:
   45|  1.66M|simdutf_really_inline bool buf_block_reader<STEP_SIZE>::has_full_block() const {
   46|  1.66M|  return idx < lenminusstep;
   47|  1.66M|}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_116buf_block_readerILm64EE10full_blockEv:
   51|  1.65M|buf_block_reader<STEP_SIZE>::full_block() const {
   52|  1.65M|  return &buf[idx];
   53|  1.65M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116buf_block_readerILm64EE7advanceEv:
   69|  1.66M|simdutf_really_inline void buf_block_reader<STEP_SIZE>::advance() {
   70|  1.66M|  idx += STEP_SIZE;
   71|  1.66M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116buf_block_readerILm64EEC2EPKhm:
   36|  2.23k|    : buf{_buf}, len{_len}, lenminusstep{len < STEP_SIZE ? 0 : len - STEP_SIZE},
  ------------------
  |  Branch (36:42): [True: 1.53k, False: 703]
  ------------------
   37|  2.23k|      idx{0} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_116buf_block_readerILm64EE14has_full_blockEv:
   45|  1.66M|simdutf_really_inline bool buf_block_reader<STEP_SIZE>::has_full_block() const {
   46|  1.66M|  return idx < lenminusstep;
   47|  1.66M|}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_116buf_block_readerILm64EE10full_blockEv:
   51|  1.65M|buf_block_reader<STEP_SIZE>::full_block() const {
   52|  1.65M|  return &buf[idx];
   53|  1.65M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116buf_block_readerILm64EE7advanceEv:
   69|  1.66M|simdutf_really_inline void buf_block_reader<STEP_SIZE>::advance() {
   70|  1.66M|  idx += STEP_SIZE;
   71|  1.66M|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1631utf8_length_from_utf16_bytemaskILNS_10endiannessE0EEEmPKDsm:
   10|    374|                                                             size_t size) {
   11|    374|  size_t pos = 0;
   12|       |
   13|    374|  using vector_u16 = simd16<uint16_t>;
   14|    374|  constexpr size_t N = vector_u16::ELEMENTS;
   15|       |
   16|    374|  const auto one = vector_u16::splat(1);
   17|       |
   18|    374|  auto v_count = vector_u16::zero();
   19|       |
   20|       |  // each char16 yields at least one byte
   21|    374|  size_t count = size / N * N;
   22|       |
   23|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
   24|       |  // three additions
   25|    374|  constexpr size_t max_iterations = 65535 / 2;
   26|    374|  size_t iteration = max_iterations;
   27|       |
   28|   620k|  for (; pos < size / N * N; pos += N) {
  ------------------
  |  Branch (28:10): [True: 620k, False: 374]
  ------------------
   29|   620k|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
   30|       |    if constexpr (!match_system(big_endian)) {
   31|       |      input = input.swap_bytes();
   32|       |    }
   33|       |    // 0xd800 .. 0xdbff - low surrogate
   34|       |    // 0xdc00 .. 0xdfff - high surrogate
   35|   620k|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
   36|       |
   37|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
   38|   620k|    const auto c0 = min(input & uint16_t(0xff80), one);
   39|       |
   40|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
   41|   620k|    const auto c1 = min(input & uint16_t(0xf800), one);
   42|       |
   43|       |    /*
   44|       |        Explanation how the counting works.
   45|       |
   46|       |        In the case of a non-surrogate character we count:
   47|       |        * always 1 -- see how `count` is initialized above;
   48|       |        * c0 = 1 if the current char yields 2 or 3 bytes;
   49|       |        * c1 = 1 if the current char yields 3 bytes.
   50|       |
   51|       |        Thus, we always have correct count for the current char:
   52|       |        from 1, 2 or 3 bytes.
   53|       |
   54|       |        A trickier part is how we count surrogate pairs. Whether
   55|       |        we encounter a surrogate (low or high), we count it as
   56|       |        3 chars and then minus 1 (`is_surrogate` is -1 or 0).
   57|       |        Each surrogate char yields 2. A surrogate pair, that
   58|       |        is a low surrogate followed by a high one, yields
   59|       |        the expected 4 bytes.
   60|       |
   61|       |        It also correctly handles cases when low surrogate is
   62|       |        processed by the this loop, but high surrogate is counted
   63|       |        by the scalar procedure. The scalar procedure uses exactly
   64|       |        the described approach, thanks to that for valid UTF-16
   65|       |        strings it always count correctly.
   66|       |    */
   67|   620k|    v_count += c0;
   68|   620k|    v_count += c1;
   69|   620k|    v_count += vector_u16(is_surrogate);
   70|       |
   71|   620k|    iteration -= 1;
   72|   620k|    if (iteration == 0) {
  ------------------
  |  Branch (72:9): [True: 16, False: 620k]
  ------------------
   73|     16|      count += v_count.sum();
   74|     16|      v_count = vector_u16::zero();
   75|     16|      iteration = max_iterations;
   76|     16|    }
   77|   620k|  }
   78|       |
   79|    374|  if (iteration > 0) {
  ------------------
  |  Branch (79:7): [True: 374, False: 0]
  ------------------
   80|    374|    count += v_count.sum();
   81|    374|  }
   82|       |
   83|    374|  return count + scalar::utf16::utf8_length_from_utf16<big_endian>(in + pos,
   84|    374|                                                                   size - pos);
   85|    374|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1631utf8_length_from_utf16_bytemaskILNS_10endiannessE1EEEmPKDsm:
   10|    389|                                                             size_t size) {
   11|    389|  size_t pos = 0;
   12|       |
   13|    389|  using vector_u16 = simd16<uint16_t>;
   14|    389|  constexpr size_t N = vector_u16::ELEMENTS;
   15|       |
   16|    389|  const auto one = vector_u16::splat(1);
   17|       |
   18|    389|  auto v_count = vector_u16::zero();
   19|       |
   20|       |  // each char16 yields at least one byte
   21|    389|  size_t count = size / N * N;
   22|       |
   23|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
   24|       |  // three additions
   25|    389|  constexpr size_t max_iterations = 65535 / 2;
   26|    389|  size_t iteration = max_iterations;
   27|       |
   28|   508k|  for (; pos < size / N * N; pos += N) {
  ------------------
  |  Branch (28:10): [True: 507k, False: 389]
  ------------------
   29|   507k|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
   30|   507k|    if constexpr (!match_system(big_endian)) {
   31|   507k|      input = input.swap_bytes();
   32|   507k|    }
   33|       |    // 0xd800 .. 0xdbff - low surrogate
   34|       |    // 0xdc00 .. 0xdfff - high surrogate
   35|   507k|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
   36|       |
   37|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
   38|   507k|    const auto c0 = min(input & uint16_t(0xff80), one);
   39|       |
   40|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
   41|   507k|    const auto c1 = min(input & uint16_t(0xf800), one);
   42|       |
   43|       |    /*
   44|       |        Explanation how the counting works.
   45|       |
   46|       |        In the case of a non-surrogate character we count:
   47|       |        * always 1 -- see how `count` is initialized above;
   48|       |        * c0 = 1 if the current char yields 2 or 3 bytes;
   49|       |        * c1 = 1 if the current char yields 3 bytes.
   50|       |
   51|       |        Thus, we always have correct count for the current char:
   52|       |        from 1, 2 or 3 bytes.
   53|       |
   54|       |        A trickier part is how we count surrogate pairs. Whether
   55|       |        we encounter a surrogate (low or high), we count it as
   56|       |        3 chars and then minus 1 (`is_surrogate` is -1 or 0).
   57|       |        Each surrogate char yields 2. A surrogate pair, that
   58|       |        is a low surrogate followed by a high one, yields
   59|       |        the expected 4 bytes.
   60|       |
   61|       |        It also correctly handles cases when low surrogate is
   62|       |        processed by the this loop, but high surrogate is counted
   63|       |        by the scalar procedure. The scalar procedure uses exactly
   64|       |        the described approach, thanks to that for valid UTF-16
   65|       |        strings it always count correctly.
   66|       |    */
   67|   507k|    v_count += c0;
   68|   507k|    v_count += c1;
   69|   507k|    v_count += vector_u16(is_surrogate);
   70|       |
   71|   507k|    iteration -= 1;
   72|   507k|    if (iteration == 0) {
  ------------------
  |  Branch (72:9): [True: 9, False: 507k]
  ------------------
   73|      9|      count += v_count.sum();
   74|      9|      v_count = vector_u16::zero();
   75|      9|      iteration = max_iterations;
   76|      9|    }
   77|   507k|  }
   78|       |
   79|    389|  if (iteration > 0) {
  ------------------
  |  Branch (79:7): [True: 389, False: 0]
  ------------------
   80|    389|    count += v_count.sum();
   81|    389|  }
   82|       |
   83|    389|  return count + scalar::utf16::utf8_length_from_utf16<big_endian>(in + pos,
   84|    389|                                                                   size - pos);
   85|    389|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE0EEENS_6resultEPKDsm:
   89|  1.11k|utf8_length_from_utf16_with_replacement(const char16_t *in, size_t size) {
   90|  1.11k|  using vector_u16 = simd16<uint16_t>;
   91|  1.11k|  constexpr size_t N = vector_u16::ELEMENTS;
   92|  1.11k|  if (N + 1 > size) {
  ------------------
  |  Branch (92:7): [True: 496, False: 614]
  ------------------
   93|    496|    return scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
   94|    496|        in, size);
   95|    496|  } // special case for short inputs
   96|    614|  size_t pos = 0;
   97|    614|  bool any_surrogates = false;
   98|       |
   99|    614|  const auto one = vector_u16::splat(1);
  100|       |
  101|    614|  auto v_count = vector_u16::zero();
  102|    614|  auto v_mismatched_count = vector_u16::zero();
  103|       |
  104|    614|  size_t count = 0;
  105|    614|  size_t mismatched_count = 0;
  106|       |
  107|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
  108|       |  // three additions
  109|    614|  constexpr size_t max_iterations = 65535 / 2;
  110|    614|  size_t iteration = max_iterations;
  111|       |
  112|    614|  if (scalar::utf16::is_low_surrogate<big_endian>(in[0])) {
  ------------------
  |  Branch (112:7): [True: 44, False: 570]
  ------------------
  113|     44|    any_surrogates = true;
  114|     44|    mismatched_count += 1;
  115|     44|  }
  116|       |
  117|  1.58M|  for (; pos < (size - 1) / N * N; pos += N) {
  ------------------
  |  Branch (117:10): [True: 1.57M, False: 614]
  ------------------
  118|  1.57M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
  119|       |    if constexpr (!match_system(big_endian)) {
  120|       |      input = input.swap_bytes();
  121|       |    }
  122|       |    // 0xd800 .. 0xdbff - low surrogate
  123|       |    // 0xdc00 .. 0xdfff - high surrogate
  124|  1.57M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
  125|       |
  126|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
  127|  1.57M|    const auto c0 = min(input & uint16_t(0xff80), one);
  128|       |
  129|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
  130|  1.57M|    const auto c1 = min(input & uint16_t(0xf800), one);
  131|       |
  132|  1.57M|    v_count += c0;
  133|  1.57M|    v_count += c1;
  134|  1.57M|    v_count += vector_u16(is_surrogate);
  135|  1.57M|    if (is_surrogate.to_bitmask() != 0 ||
  ------------------
  |  Branch (135:9): [True: 197k, False: 1.38M]
  ------------------
  136|  1.38M|        scalar::utf16::is_low_surrogate<big_endian>(in[pos + N])) {
  ------------------
  |  Branch (136:9): [True: 2.69k, False: 1.37M]
  ------------------
  137|   200k|      any_surrogates = true;
  138|   200k|      auto input_next =
  139|   200k|          vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos + 1));
  140|       |      if constexpr (!match_system(big_endian)) {
  141|       |        input_next = input_next.swap_bytes();
  142|       |      }
  143|       |
  144|   200k|      const auto lb_masked = input & (0xfc00);
  145|   200k|      const auto block_masked = input_next & (0xfc00);
  146|       |
  147|   200k|      const auto lb_is_high = lb_masked == (0xd800);
  148|   200k|      const auto block_is_low = block_masked == (0xdc00);
  149|       |
  150|   200k|      const auto illseq = min(vector_u16(lb_is_high ^ block_is_low), one);
  151|       |
  152|   200k|      v_mismatched_count += illseq;
  153|   200k|    }
  154|       |
  155|  1.57M|    iteration -= 1;
  156|  1.57M|    if (iteration == 0) {
  ------------------
  |  Branch (156:9): [True: 32, False: 1.57M]
  ------------------
  157|     32|      count += v_count.sum();
  158|     32|      v_count = vector_u16::zero();
  159|     32|      mismatched_count += v_mismatched_count.sum();
  160|     32|      v_mismatched_count = vector_u16::zero();
  161|     32|      iteration = max_iterations;
  162|     32|    }
  163|  1.57M|  }
  164|       |
  165|    614|  if (iteration > 0) {
  ------------------
  |  Branch (165:7): [True: 614, False: 0]
  ------------------
  166|    614|    count += v_count.sum();
  167|    614|    mismatched_count += v_mismatched_count.sum();
  168|    614|  }
  169|       |
  170|    614|  if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (170:7): [True: 98, False: 516]
  ------------------
  171|     98|    any_surrogates = true;
  172|     98|    if (!scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (172:9): [True: 69, False: 29]
  ------------------
  173|     69|      mismatched_count -= 1;
  174|     69|      count += 2;
  175|     69|      pos += 1;
  176|     69|    }
  177|     98|  }
  178|    614|  count += pos;
  179|    614|  count += mismatched_count;
  180|    614|  if (scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (180:7): [True: 121, False: 493]
  ------------------
  181|    121|    any_surrogates = true;
  182|    121|    if (pos == size) {
  ------------------
  |  Branch (182:9): [True: 0, False: 121]
  ------------------
  183|      0|      count += 2;
  184|    121|    } else if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (184:16): [True: 29, False: 92]
  ------------------
  185|     29|      pos += 1;
  186|     29|      count += 2;
  187|     29|    }
  188|    121|  }
  189|    614|  result scalar_result =
  190|    614|      scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
  191|    614|          in + pos, size - pos);
  192|    614|  return {any_surrogates ? SURROGATE : scalar_result.error,
  ------------------
  |  Branch (192:11): [True: 385, False: 229]
  ------------------
  193|    614|          count + scalar_result.count};
  194|  1.11k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE1EEENS_6resultEPKDsm:
   89|  1.12k|utf8_length_from_utf16_with_replacement(const char16_t *in, size_t size) {
   90|  1.12k|  using vector_u16 = simd16<uint16_t>;
   91|  1.12k|  constexpr size_t N = vector_u16::ELEMENTS;
   92|  1.12k|  if (N + 1 > size) {
  ------------------
  |  Branch (92:7): [True: 507, False: 617]
  ------------------
   93|    507|    return scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
   94|    507|        in, size);
   95|    507|  } // special case for short inputs
   96|    617|  size_t pos = 0;
   97|    617|  bool any_surrogates = false;
   98|       |
   99|    617|  const auto one = vector_u16::splat(1);
  100|       |
  101|    617|  auto v_count = vector_u16::zero();
  102|    617|  auto v_mismatched_count = vector_u16::zero();
  103|       |
  104|    617|  size_t count = 0;
  105|    617|  size_t mismatched_count = 0;
  106|       |
  107|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
  108|       |  // three additions
  109|    617|  constexpr size_t max_iterations = 65535 / 2;
  110|    617|  size_t iteration = max_iterations;
  111|       |
  112|    617|  if (scalar::utf16::is_low_surrogate<big_endian>(in[0])) {
  ------------------
  |  Branch (112:7): [True: 46, False: 571]
  ------------------
  113|     46|    any_surrogates = true;
  114|     46|    mismatched_count += 1;
  115|     46|  }
  116|       |
  117|  1.33M|  for (; pos < (size - 1) / N * N; pos += N) {
  ------------------
  |  Branch (117:10): [True: 1.33M, False: 617]
  ------------------
  118|  1.33M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
  119|  1.33M|    if constexpr (!match_system(big_endian)) {
  120|  1.33M|      input = input.swap_bytes();
  121|  1.33M|    }
  122|       |    // 0xd800 .. 0xdbff - low surrogate
  123|       |    // 0xdc00 .. 0xdfff - high surrogate
  124|  1.33M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
  125|       |
  126|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
  127|  1.33M|    const auto c0 = min(input & uint16_t(0xff80), one);
  128|       |
  129|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
  130|  1.33M|    const auto c1 = min(input & uint16_t(0xf800), one);
  131|       |
  132|  1.33M|    v_count += c0;
  133|  1.33M|    v_count += c1;
  134|  1.33M|    v_count += vector_u16(is_surrogate);
  135|  1.33M|    if (is_surrogate.to_bitmask() != 0 ||
  ------------------
  |  Branch (135:9): [True: 128k, False: 1.20M]
  ------------------
  136|  1.20M|        scalar::utf16::is_low_surrogate<big_endian>(in[pos + N])) {
  ------------------
  |  Branch (136:9): [True: 1.83k, False: 1.20M]
  ------------------
  137|   130k|      any_surrogates = true;
  138|   130k|      auto input_next =
  139|   130k|          vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos + 1));
  140|   130k|      if constexpr (!match_system(big_endian)) {
  141|   130k|        input_next = input_next.swap_bytes();
  142|   130k|      }
  143|       |
  144|   130k|      const auto lb_masked = input & (0xfc00);
  145|   130k|      const auto block_masked = input_next & (0xfc00);
  146|       |
  147|   130k|      const auto lb_is_high = lb_masked == (0xd800);
  148|   130k|      const auto block_is_low = block_masked == (0xdc00);
  149|       |
  150|   130k|      const auto illseq = min(vector_u16(lb_is_high ^ block_is_low), one);
  151|       |
  152|   130k|      v_mismatched_count += illseq;
  153|   130k|    }
  154|       |
  155|  1.33M|    iteration -= 1;
  156|  1.33M|    if (iteration == 0) {
  ------------------
  |  Branch (156:9): [True: 22, False: 1.33M]
  ------------------
  157|     22|      count += v_count.sum();
  158|     22|      v_count = vector_u16::zero();
  159|     22|      mismatched_count += v_mismatched_count.sum();
  160|     22|      v_mismatched_count = vector_u16::zero();
  161|     22|      iteration = max_iterations;
  162|     22|    }
  163|  1.33M|  }
  164|       |
  165|    617|  if (iteration > 0) {
  ------------------
  |  Branch (165:7): [True: 617, False: 0]
  ------------------
  166|    617|    count += v_count.sum();
  167|    617|    mismatched_count += v_mismatched_count.sum();
  168|    617|  }
  169|       |
  170|    617|  if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (170:7): [True: 114, False: 503]
  ------------------
  171|    114|    any_surrogates = true;
  172|    114|    if (!scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (172:9): [True: 84, False: 30]
  ------------------
  173|     84|      mismatched_count -= 1;
  174|     84|      count += 2;
  175|     84|      pos += 1;
  176|     84|    }
  177|    114|  }
  178|    617|  count += pos;
  179|    617|  count += mismatched_count;
  180|    617|  if (scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (180:7): [True: 110, False: 507]
  ------------------
  181|    110|    any_surrogates = true;
  182|    110|    if (pos == size) {
  ------------------
  |  Branch (182:9): [True: 0, False: 110]
  ------------------
  183|      0|      count += 2;
  184|    110|    } else if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (184:16): [True: 30, False: 80]
  ------------------
  185|     30|      pos += 1;
  186|     30|      count += 2;
  187|     30|    }
  188|    110|  }
  189|    617|  result scalar_result =
  190|    617|      scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
  191|    617|          in + pos, size - pos);
  192|    617|  return {any_surrogates ? SURROGATE : scalar_result.error,
  ------------------
  |  Branch (192:11): [True: 385, False: 232]
  ------------------
  193|    617|          count + scalar_result.count};
  194|  1.12k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1631utf8_length_from_utf16_bytemaskILNS_10endiannessE0EEEmPKDsm:
   10|    374|                                                             size_t size) {
   11|    374|  size_t pos = 0;
   12|       |
   13|    374|  using vector_u16 = simd16<uint16_t>;
   14|    374|  constexpr size_t N = vector_u16::ELEMENTS;
   15|       |
   16|    374|  const auto one = vector_u16::splat(1);
   17|       |
   18|    374|  auto v_count = vector_u16::zero();
   19|       |
   20|       |  // each char16 yields at least one byte
   21|    374|  size_t count = size / N * N;
   22|       |
   23|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
   24|       |  // three additions
   25|    374|  constexpr size_t max_iterations = 65535 / 2;
   26|    374|  size_t iteration = max_iterations;
   27|       |
   28|  1.24M|  for (; pos < size / N * N; pos += N) {
  ------------------
  |  Branch (28:10): [True: 1.24M, False: 374]
  ------------------
   29|  1.24M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
   30|       |    if constexpr (!match_system(big_endian)) {
   31|       |      input = input.swap_bytes();
   32|       |    }
   33|       |    // 0xd800 .. 0xdbff - low surrogate
   34|       |    // 0xdc00 .. 0xdfff - high surrogate
   35|  1.24M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
   36|       |
   37|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
   38|  1.24M|    const auto c0 = min(input & uint16_t(0xff80), one);
   39|       |
   40|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
   41|  1.24M|    const auto c1 = min(input & uint16_t(0xf800), one);
   42|       |
   43|       |    /*
   44|       |        Explanation how the counting works.
   45|       |
   46|       |        In the case of a non-surrogate character we count:
   47|       |        * always 1 -- see how `count` is initialized above;
   48|       |        * c0 = 1 if the current char yields 2 or 3 bytes;
   49|       |        * c1 = 1 if the current char yields 3 bytes.
   50|       |
   51|       |        Thus, we always have correct count for the current char:
   52|       |        from 1, 2 or 3 bytes.
   53|       |
   54|       |        A trickier part is how we count surrogate pairs. Whether
   55|       |        we encounter a surrogate (low or high), we count it as
   56|       |        3 chars and then minus 1 (`is_surrogate` is -1 or 0).
   57|       |        Each surrogate char yields 2. A surrogate pair, that
   58|       |        is a low surrogate followed by a high one, yields
   59|       |        the expected 4 bytes.
   60|       |
   61|       |        It also correctly handles cases when low surrogate is
   62|       |        processed by the this loop, but high surrogate is counted
   63|       |        by the scalar procedure. The scalar procedure uses exactly
   64|       |        the described approach, thanks to that for valid UTF-16
   65|       |        strings it always count correctly.
   66|       |    */
   67|  1.24M|    v_count += c0;
   68|  1.24M|    v_count += c1;
   69|  1.24M|    v_count += vector_u16(is_surrogate);
   70|       |
   71|  1.24M|    iteration -= 1;
   72|  1.24M|    if (iteration == 0) {
  ------------------
  |  Branch (72:9): [True: 33, False: 1.24M]
  ------------------
   73|     33|      count += v_count.sum();
   74|     33|      v_count = vector_u16::zero();
   75|     33|      iteration = max_iterations;
   76|     33|    }
   77|  1.24M|  }
   78|       |
   79|    374|  if (iteration > 0) {
  ------------------
  |  Branch (79:7): [True: 374, False: 0]
  ------------------
   80|    374|    count += v_count.sum();
   81|    374|  }
   82|       |
   83|    374|  return count + scalar::utf16::utf8_length_from_utf16<big_endian>(in + pos,
   84|    374|                                                                   size - pos);
   85|    374|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1631utf8_length_from_utf16_bytemaskILNS_10endiannessE1EEEmPKDsm:
   10|    389|                                                             size_t size) {
   11|    389|  size_t pos = 0;
   12|       |
   13|    389|  using vector_u16 = simd16<uint16_t>;
   14|    389|  constexpr size_t N = vector_u16::ELEMENTS;
   15|       |
   16|    389|  const auto one = vector_u16::splat(1);
   17|       |
   18|    389|  auto v_count = vector_u16::zero();
   19|       |
   20|       |  // each char16 yields at least one byte
   21|    389|  size_t count = size / N * N;
   22|       |
   23|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
   24|       |  // three additions
   25|    389|  constexpr size_t max_iterations = 65535 / 2;
   26|    389|  size_t iteration = max_iterations;
   27|       |
   28|  1.01M|  for (; pos < size / N * N; pos += N) {
  ------------------
  |  Branch (28:10): [True: 1.01M, False: 389]
  ------------------
   29|  1.01M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
   30|  1.01M|    if constexpr (!match_system(big_endian)) {
   31|  1.01M|      input = input.swap_bytes();
   32|  1.01M|    }
   33|       |    // 0xd800 .. 0xdbff - low surrogate
   34|       |    // 0xdc00 .. 0xdfff - high surrogate
   35|  1.01M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
   36|       |
   37|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
   38|  1.01M|    const auto c0 = min(input & uint16_t(0xff80), one);
   39|       |
   40|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
   41|  1.01M|    const auto c1 = min(input & uint16_t(0xf800), one);
   42|       |
   43|       |    /*
   44|       |        Explanation how the counting works.
   45|       |
   46|       |        In the case of a non-surrogate character we count:
   47|       |        * always 1 -- see how `count` is initialized above;
   48|       |        * c0 = 1 if the current char yields 2 or 3 bytes;
   49|       |        * c1 = 1 if the current char yields 3 bytes.
   50|       |
   51|       |        Thus, we always have correct count for the current char:
   52|       |        from 1, 2 or 3 bytes.
   53|       |
   54|       |        A trickier part is how we count surrogate pairs. Whether
   55|       |        we encounter a surrogate (low or high), we count it as
   56|       |        3 chars and then minus 1 (`is_surrogate` is -1 or 0).
   57|       |        Each surrogate char yields 2. A surrogate pair, that
   58|       |        is a low surrogate followed by a high one, yields
   59|       |        the expected 4 bytes.
   60|       |
   61|       |        It also correctly handles cases when low surrogate is
   62|       |        processed by the this loop, but high surrogate is counted
   63|       |        by the scalar procedure. The scalar procedure uses exactly
   64|       |        the described approach, thanks to that for valid UTF-16
   65|       |        strings it always count correctly.
   66|       |    */
   67|  1.01M|    v_count += c0;
   68|  1.01M|    v_count += c1;
   69|  1.01M|    v_count += vector_u16(is_surrogate);
   70|       |
   71|  1.01M|    iteration -= 1;
   72|  1.01M|    if (iteration == 0) {
  ------------------
  |  Branch (72:9): [True: 23, False: 1.01M]
  ------------------
   73|     23|      count += v_count.sum();
   74|     23|      v_count = vector_u16::zero();
   75|     23|      iteration = max_iterations;
   76|     23|    }
   77|  1.01M|  }
   78|       |
   79|    389|  if (iteration > 0) {
  ------------------
  |  Branch (79:7): [True: 389, False: 0]
  ------------------
   80|    389|    count += v_count.sum();
   81|    389|  }
   82|       |
   83|    389|  return count + scalar::utf16::utf8_length_from_utf16<big_endian>(in + pos,
   84|    389|                                                                   size - pos);
   85|    389|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE0EEENS_6resultEPKDsm:
   89|  1.11k|utf8_length_from_utf16_with_replacement(const char16_t *in, size_t size) {
   90|  1.11k|  using vector_u16 = simd16<uint16_t>;
   91|  1.11k|  constexpr size_t N = vector_u16::ELEMENTS;
   92|  1.11k|  if (N + 1 > size) {
  ------------------
  |  Branch (92:7): [True: 223, False: 887]
  ------------------
   93|    223|    return scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
   94|    223|        in, size);
   95|    223|  } // special case for short inputs
   96|    887|  size_t pos = 0;
   97|    887|  bool any_surrogates = false;
   98|       |
   99|    887|  const auto one = vector_u16::splat(1);
  100|       |
  101|    887|  auto v_count = vector_u16::zero();
  102|    887|  auto v_mismatched_count = vector_u16::zero();
  103|       |
  104|    887|  size_t count = 0;
  105|    887|  size_t mismatched_count = 0;
  106|       |
  107|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
  108|       |  // three additions
  109|    887|  constexpr size_t max_iterations = 65535 / 2;
  110|    887|  size_t iteration = max_iterations;
  111|       |
  112|    887|  if (scalar::utf16::is_low_surrogate<big_endian>(in[0])) {
  ------------------
  |  Branch (112:7): [True: 73, False: 814]
  ------------------
  113|     73|    any_surrogates = true;
  114|     73|    mismatched_count += 1;
  115|     73|  }
  116|       |
  117|  3.16M|  for (; pos < (size - 1) / N * N; pos += N) {
  ------------------
  |  Branch (117:10): [True: 3.16M, False: 887]
  ------------------
  118|  3.16M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
  119|       |    if constexpr (!match_system(big_endian)) {
  120|       |      input = input.swap_bytes();
  121|       |    }
  122|       |    // 0xd800 .. 0xdbff - low surrogate
  123|       |    // 0xdc00 .. 0xdfff - high surrogate
  124|  3.16M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
  125|       |
  126|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
  127|  3.16M|    const auto c0 = min(input & uint16_t(0xff80), one);
  128|       |
  129|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
  130|  3.16M|    const auto c1 = min(input & uint16_t(0xf800), one);
  131|       |
  132|  3.16M|    v_count += c0;
  133|  3.16M|    v_count += c1;
  134|  3.16M|    v_count += vector_u16(is_surrogate);
  135|  3.16M|    if (is_surrogate.to_bitmask() != 0 ||
  ------------------
  |  Branch (135:9): [True: 307k, False: 2.85M]
  ------------------
  136|  2.85M|        scalar::utf16::is_low_surrogate<big_endian>(in[pos + N])) {
  ------------------
  |  Branch (136:9): [True: 7.42k, False: 2.84M]
  ------------------
  137|   314k|      any_surrogates = true;
  138|   314k|      auto input_next =
  139|   314k|          vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos + 1));
  140|       |      if constexpr (!match_system(big_endian)) {
  141|       |        input_next = input_next.swap_bytes();
  142|       |      }
  143|       |
  144|   314k|      const auto lb_masked = input & (0xfc00);
  145|   314k|      const auto block_masked = input_next & (0xfc00);
  146|       |
  147|   314k|      const auto lb_is_high = lb_masked == (0xd800);
  148|   314k|      const auto block_is_low = block_masked == (0xdc00);
  149|       |
  150|   314k|      const auto illseq = min(vector_u16(lb_is_high ^ block_is_low), one);
  151|       |
  152|   314k|      v_mismatched_count += illseq;
  153|   314k|    }
  154|       |
  155|  3.16M|    iteration -= 1;
  156|  3.16M|    if (iteration == 0) {
  ------------------
  |  Branch (156:9): [True: 76, False: 3.16M]
  ------------------
  157|     76|      count += v_count.sum();
  158|     76|      v_count = vector_u16::zero();
  159|     76|      mismatched_count += v_mismatched_count.sum();
  160|     76|      v_mismatched_count = vector_u16::zero();
  161|     76|      iteration = max_iterations;
  162|     76|    }
  163|  3.16M|  }
  164|       |
  165|    887|  if (iteration > 0) {
  ------------------
  |  Branch (165:7): [True: 887, False: 0]
  ------------------
  166|    887|    count += v_count.sum();
  167|    887|    mismatched_count += v_mismatched_count.sum();
  168|    887|  }
  169|       |
  170|    887|  if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (170:7): [True: 173, False: 714]
  ------------------
  171|    173|    any_surrogates = true;
  172|    173|    if (!scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (172:9): [True: 121, False: 52]
  ------------------
  173|    121|      mismatched_count -= 1;
  174|    121|      count += 2;
  175|    121|      pos += 1;
  176|    121|    }
  177|    173|  }
  178|    887|  count += pos;
  179|    887|  count += mismatched_count;
  180|    887|  if (scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (180:7): [True: 195, False: 692]
  ------------------
  181|    195|    any_surrogates = true;
  182|    195|    if (pos == size) {
  ------------------
  |  Branch (182:9): [True: 0, False: 195]
  ------------------
  183|      0|      count += 2;
  184|    195|    } else if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (184:16): [True: 52, False: 143]
  ------------------
  185|     52|      pos += 1;
  186|     52|      count += 2;
  187|     52|    }
  188|    195|  }
  189|    887|  result scalar_result =
  190|    887|      scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
  191|    887|          in + pos, size - pos);
  192|    887|  return {any_surrogates ? SURROGATE : scalar_result.error,
  ------------------
  |  Branch (192:11): [True: 565, False: 322]
  ------------------
  193|    887|          count + scalar_result.count};
  194|  1.11k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1639utf8_length_from_utf16_with_replacementILNS_10endiannessE1EEENS_6resultEPKDsm:
   89|  1.12k|utf8_length_from_utf16_with_replacement(const char16_t *in, size_t size) {
   90|  1.12k|  using vector_u16 = simd16<uint16_t>;
   91|  1.12k|  constexpr size_t N = vector_u16::ELEMENTS;
   92|  1.12k|  if (N + 1 > size) {
  ------------------
  |  Branch (92:7): [True: 224, False: 900]
  ------------------
   93|    224|    return scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
   94|    224|        in, size);
   95|    224|  } // special case for short inputs
   96|    900|  size_t pos = 0;
   97|    900|  bool any_surrogates = false;
   98|       |
   99|    900|  const auto one = vector_u16::splat(1);
  100|       |
  101|    900|  auto v_count = vector_u16::zero();
  102|    900|  auto v_mismatched_count = vector_u16::zero();
  103|       |
  104|    900|  size_t count = 0;
  105|    900|  size_t mismatched_count = 0;
  106|       |
  107|       |  // in a single iteration the increment is 0, 1 or 2, despite we have
  108|       |  // three additions
  109|    900|  constexpr size_t max_iterations = 65535 / 2;
  110|    900|  size_t iteration = max_iterations;
  111|       |
  112|    900|  if (scalar::utf16::is_low_surrogate<big_endian>(in[0])) {
  ------------------
  |  Branch (112:7): [True: 78, False: 822]
  ------------------
  113|     78|    any_surrogates = true;
  114|     78|    mismatched_count += 1;
  115|     78|  }
  116|       |
  117|  2.66M|  for (; pos < (size - 1) / N * N; pos += N) {
  ------------------
  |  Branch (117:10): [True: 2.66M, False: 900]
  ------------------
  118|  2.66M|    auto input = vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos));
  119|  2.66M|    if constexpr (!match_system(big_endian)) {
  120|  2.66M|      input = input.swap_bytes();
  121|  2.66M|    }
  122|       |    // 0xd800 .. 0xdbff - low surrogate
  123|       |    // 0xdc00 .. 0xdfff - high surrogate
  124|  2.66M|    const auto is_surrogate = ((input & uint16_t(0xf800)) == uint16_t(0xd800));
  125|       |
  126|       |    // c0 - chars that yield 2- or 3-byte UTF-8 codes
  127|  2.66M|    const auto c0 = min(input & uint16_t(0xff80), one);
  128|       |
  129|       |    // c1 - chars that yield 3-byte UTF-8 codes (including surrogates)
  130|  2.66M|    const auto c1 = min(input & uint16_t(0xf800), one);
  131|       |
  132|  2.66M|    v_count += c0;
  133|  2.66M|    v_count += c1;
  134|  2.66M|    v_count += vector_u16(is_surrogate);
  135|  2.66M|    if (is_surrogate.to_bitmask() != 0 ||
  ------------------
  |  Branch (135:9): [True: 198k, False: 2.46M]
  ------------------
  136|  2.46M|        scalar::utf16::is_low_surrogate<big_endian>(in[pos + N])) {
  ------------------
  |  Branch (136:9): [True: 5.18k, False: 2.46M]
  ------------------
  137|   203k|      any_surrogates = true;
  138|   203k|      auto input_next =
  139|   203k|          vector_u16::load(reinterpret_cast<const uint16_t *>(in + pos + 1));
  140|   203k|      if constexpr (!match_system(big_endian)) {
  141|   203k|        input_next = input_next.swap_bytes();
  142|   203k|      }
  143|       |
  144|   203k|      const auto lb_masked = input & (0xfc00);
  145|   203k|      const auto block_masked = input_next & (0xfc00);
  146|       |
  147|   203k|      const auto lb_is_high = lb_masked == (0xd800);
  148|   203k|      const auto block_is_low = block_masked == (0xdc00);
  149|       |
  150|   203k|      const auto illseq = min(vector_u16(lb_is_high ^ block_is_low), one);
  151|       |
  152|   203k|      v_mismatched_count += illseq;
  153|   203k|    }
  154|       |
  155|  2.66M|    iteration -= 1;
  156|  2.66M|    if (iteration == 0) {
  ------------------
  |  Branch (156:9): [True: 57, False: 2.66M]
  ------------------
  157|     57|      count += v_count.sum();
  158|     57|      v_count = vector_u16::zero();
  159|     57|      mismatched_count += v_mismatched_count.sum();
  160|     57|      v_mismatched_count = vector_u16::zero();
  161|     57|      iteration = max_iterations;
  162|     57|    }
  163|  2.66M|  }
  164|       |
  165|    900|  if (iteration > 0) {
  ------------------
  |  Branch (165:7): [True: 900, False: 0]
  ------------------
  166|    900|    count += v_count.sum();
  167|    900|    mismatched_count += v_mismatched_count.sum();
  168|    900|  }
  169|       |
  170|    900|  if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (170:7): [True: 202, False: 698]
  ------------------
  171|    202|    any_surrogates = true;
  172|    202|    if (!scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (172:9): [True: 152, False: 50]
  ------------------
  173|    152|      mismatched_count -= 1;
  174|    152|      count += 2;
  175|    152|      pos += 1;
  176|    152|    }
  177|    202|  }
  178|    900|  count += pos;
  179|    900|  count += mismatched_count;
  180|    900|  if (scalar::utf16::is_high_surrogate<big_endian>(in[pos - 1])) {
  ------------------
  |  Branch (180:7): [True: 186, False: 714]
  ------------------
  181|    186|    any_surrogates = true;
  182|    186|    if (pos == size) {
  ------------------
  |  Branch (182:9): [True: 0, False: 186]
  ------------------
  183|      0|      count += 2;
  184|    186|    } else if (scalar::utf16::is_low_surrogate<big_endian>(in[pos])) {
  ------------------
  |  Branch (184:16): [True: 50, False: 136]
  ------------------
  185|     50|      pos += 1;
  186|     50|      count += 2;
  187|     50|    }
  188|    186|  }
  189|    900|  result scalar_result =
  190|    900|      scalar::utf16::utf8_length_from_utf16_with_replacement<big_endian>(
  191|    900|          in + pos, size - pos);
  192|    900|  return {any_surrogates ? SURROGATE : scalar_result.error,
  ------------------
  |  Branch (192:11): [True: 579, False: 321]
  ------------------
  193|    900|          count + scalar_result.count};
  194|  1.12k|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker16check_next_inputERKNS1_4simd8simd8x64IhEE:
  187|  1.66M|  simdutf_really_inline void check_next_input(const simd8x64<uint8_t> &input) {
  188|  1.66M|    if (simdutf_likely(is_ascii(input))) {
  ------------------
  |  |   89|  1.66M|    #define simdutf_likely(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (89:31): [True: 214k, False: 1.44M]
  |  |  ------------------
  ------------------
  189|   214k|      this->error |= this->prev_incomplete;
  190|  1.44M|    } else {
  191|       |      // you might think that a for-loop would work, but under Visual Studio, it
  192|       |      // is not good enough.
  193|  1.44M|      static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) ||
  194|  1.44M|                        (simd8x64<uint8_t>::NUM_CHUNKS == 4),
  195|  1.44M|                    "We support either two or four chunks per 64-byte block.");
  196|  1.44M|      if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
  197|  1.44M|        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  198|  1.44M|        this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
  199|       |      } else if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
  200|       |        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  201|       |        this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
  202|       |        this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
  203|       |        this->check_utf8_bytes(input.chunks[3], input.chunks[2]);
  204|       |      }
  205|  1.44M|      this->prev_incomplete =
  206|  1.44M|          is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1]);
  207|  1.44M|      this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1];
  208|  1.44M|    }
  209|  1.66M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker16check_utf8_bytesENS1_4simd5simd8IhEES6_:
  169|  2.89M|                                              const simd8<uint8_t> prev_input) {
  170|       |    // Flip prev1...prev3 so we can easily determine if they are 2+, 3+ or 4+
  171|       |    // lead bytes (2, 3, 4-byte leads become large positive numbers instead of
  172|       |    // small negative numbers)
  173|  2.89M|    simd8<uint8_t> prev1 = input.prev<1>(prev_input);
  174|  2.89M|    simd8<uint8_t> sc = check_special_cases(input, prev1);
  175|  2.89M|    this->error |= check_multibyte_lengths(input, prev_input, sc);
  176|  2.89M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation19check_special_casesENS1_4simd5simd8IhEES5_:
    9|  2.89M|check_special_cases(const simd8<uint8_t> input, const simd8<uint8_t> prev1) {
   10|       |  // Bit 0 = Too Short (lead byte/ASCII followed by lead byte/ASCII)
   11|       |  // Bit 1 = Too Long (ASCII followed by continuation)
   12|       |  // Bit 2 = Overlong 3-byte
   13|       |  // Bit 4 = Surrogate
   14|       |  // Bit 5 = Overlong 2-byte
   15|       |  // Bit 7 = Two Continuations
   16|  2.89M|  constexpr const uint8_t TOO_SHORT = 1 << 0;  // 11______ 0_______
   17|       |                                               // 11______ 11______
   18|  2.89M|  constexpr const uint8_t TOO_LONG = 1 << 1;   // 0_______ 10______
   19|  2.89M|  constexpr const uint8_t OVERLONG_3 = 1 << 2; // 11100000 100_____
   20|  2.89M|  constexpr const uint8_t SURROGATE = 1 << 4;  // 11101101 101_____
   21|  2.89M|  constexpr const uint8_t OVERLONG_2 = 1 << 5; // 1100000_ 10______
   22|  2.89M|  constexpr const uint8_t TWO_CONTS = 1 << 7;  // 10______ 10______
   23|  2.89M|  constexpr const uint8_t TOO_LARGE = 1 << 3;  // 11110100 1001____
   24|       |                                               // 11110100 101_____
   25|       |                                               // 11110101 1001____
   26|       |                                               // 11110101 101_____
   27|       |                                               // 1111011_ 1001____
   28|       |                                               // 1111011_ 101_____
   29|       |                                               // 11111___ 1001____
   30|       |                                               // 11111___ 101_____
   31|  2.89M|  constexpr const uint8_t TOO_LARGE_1000 = 1 << 6;
   32|       |  // 11110101 1000____
   33|       |  // 1111011_ 1000____
   34|       |  // 11111___ 1000____
   35|  2.89M|  constexpr const uint8_t OVERLONG_4 = 1 << 6; // 11110000 1000____
   36|       |
   37|  2.89M|  const simd8<uint8_t> byte_1_high = prev1.shr<4>().lookup_16<uint8_t>(
   38|       |      // 0_______ ________ <ASCII in byte 1>
   39|  2.89M|      TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG,
   40|  2.89M|      TOO_LONG,
   41|       |      // 10______ ________ <continuation in byte 1>
   42|  2.89M|      TWO_CONTS, TWO_CONTS, TWO_CONTS, TWO_CONTS,
   43|       |      // 1100____ ________ <two byte lead in byte 1>
   44|  2.89M|      TOO_SHORT | OVERLONG_2,
   45|       |      // 1101____ ________ <two byte lead in byte 1>
   46|  2.89M|      TOO_SHORT,
   47|       |      // 1110____ ________ <three byte lead in byte 1>
   48|  2.89M|      TOO_SHORT | OVERLONG_3 | SURROGATE,
   49|       |      // 1111____ ________ <four+ byte lead in byte 1>
   50|  2.89M|      TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4);
   51|  2.89M|  constexpr const uint8_t CARRY =
   52|  2.89M|      TOO_SHORT | TOO_LONG | TWO_CONTS; // These all have ____ in byte 1 .
   53|  2.89M|  const simd8<uint8_t> byte_1_low =
   54|  2.89M|      (prev1 & 0x0F)
   55|  2.89M|          .lookup_16<uint8_t>(
   56|       |              // ____0000 ________
   57|  2.89M|              CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4,
   58|       |              // ____0001 ________
   59|  2.89M|              CARRY | OVERLONG_2,
   60|       |              // ____001_ ________
   61|  2.89M|              CARRY, CARRY,
   62|       |
   63|       |              // ____0100 ________
   64|  2.89M|              CARRY | TOO_LARGE,
   65|       |              // ____0101 ________
   66|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   67|       |              // ____011_ ________
   68|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   69|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   70|       |
   71|       |              // ____1___ ________
   72|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   73|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   74|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   75|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   76|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   77|       |              // ____1101 ________
   78|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE,
   79|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   80|  2.89M|              CARRY | TOO_LARGE | TOO_LARGE_1000);
   81|  2.89M|  const simd8<uint8_t> byte_2_high = input.shr<4>().lookup_16<uint8_t>(
   82|       |      // ________ 0_______ <ASCII in byte 2>
   83|  2.89M|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT,
   84|  2.89M|      TOO_SHORT, TOO_SHORT,
   85|       |
   86|       |      // ________ 1000____
   87|  2.89M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 |
   88|  2.89M|          OVERLONG_4,
   89|       |      // ________ 1001____
   90|  2.89M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE,
   91|       |      // ________ 101_____
   92|  2.89M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   93|  2.89M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   94|       |
   95|       |      // ________ 11______
   96|  2.89M|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT);
   97|  2.89M|  return (byte_1_high & byte_1_low & byte_2_high);
   98|  2.89M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation23check_multibyte_lengthsENS1_4simd5simd8IhEES5_S5_:
  102|  2.89M|                        const simd8<uint8_t> sc) {
  103|  2.89M|  simd8<uint8_t> prev2 = input.prev<2>(prev_input);
  104|  2.89M|  simd8<uint8_t> prev3 = input.prev<3>(prev_input);
  105|  2.89M|  simd8<uint8_t> must23 =
  106|  2.89M|      simd8<uint8_t>(must_be_2_3_continuation(prev2, prev3));
  107|  2.89M|  simd8<uint8_t> must23_80 = must23 & uint8_t(0x80);
  108|  2.89M|  return must23_80 ^ sc;
  109|  2.89M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation13is_incompleteENS1_4simd5simd8IhEE:
  115|  1.44M|simdutf_really_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) {
  116|       |  // If the previous input's last 3 bytes match this, they're too short (they
  117|       |  // ended at EOF):
  118|       |  // ... 1111____ 111_____ 11______
  119|  1.44M|  static const uint8_t max_array[32] = {255,
  120|  1.44M|                                        255,
  121|  1.44M|                                        255,
  122|  1.44M|                                        255,
  123|  1.44M|                                        255,
  124|  1.44M|                                        255,
  125|  1.44M|                                        255,
  126|  1.44M|                                        255,
  127|  1.44M|                                        255,
  128|  1.44M|                                        255,
  129|  1.44M|                                        255,
  130|  1.44M|                                        255,
  131|  1.44M|                                        255,
  132|  1.44M|                                        255,
  133|  1.44M|                                        255,
  134|  1.44M|                                        255,
  135|  1.44M|                                        255,
  136|  1.44M|                                        255,
  137|  1.44M|                                        255,
  138|  1.44M|                                        255,
  139|  1.44M|                                        255,
  140|  1.44M|                                        255,
  141|  1.44M|                                        255,
  142|  1.44M|                                        255,
  143|  1.44M|                                        255,
  144|  1.44M|                                        255,
  145|  1.44M|                                        255,
  146|  1.44M|                                        255,
  147|  1.44M|                                        255,
  148|  1.44M|                                        0b11110000u - 1,
  149|  1.44M|                                        0b11100000u - 1,
  150|  1.44M|                                        0b11000000u - 1};
  151|  1.44M|  const simd8<uint8_t> max_value(
  152|  1.44M|      &max_array[sizeof(max_array) - sizeof(simd8<uint8_t>)]);
  153|  1.44M|  return input.gt_bits(max_value);
  154|  1.44M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker9check_eofEv:
  181|  2.23k|  simdutf_really_inline void check_eof() {
  182|       |    // If the previous block had incomplete UTF-8 characters at the end, an
  183|       |    // ASCII block can't possibly finish them.
  184|  2.23k|    this->error |= this->prev_incomplete;
  185|  2.23k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker6errorsEv:
  212|  2.23k|  simdutf_really_inline bool errors() const {
  213|  2.23k|    return this->error.any_bits_set_anywhere();
  214|  2.23k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker16check_next_inputERKNS1_4simd8simd8x64IhEE:
  187|  1.66M|  simdutf_really_inline void check_next_input(const simd8x64<uint8_t> &input) {
  188|  1.66M|    if (simdutf_likely(is_ascii(input))) {
  ------------------
  |  |   89|  1.66M|    #define simdutf_likely(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (89:31): [True: 214k, False: 1.44M]
  |  |  ------------------
  ------------------
  189|   214k|      this->error |= this->prev_incomplete;
  190|  1.44M|    } else {
  191|       |      // you might think that a for-loop would work, but under Visual Studio, it
  192|       |      // is not good enough.
  193|  1.44M|      static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) ||
  194|  1.44M|                        (simd8x64<uint8_t>::NUM_CHUNKS == 4),
  195|  1.44M|                    "We support either two or four chunks per 64-byte block.");
  196|       |      if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
  197|       |        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  198|       |        this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
  199|  1.44M|      } else if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
  200|  1.44M|        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  201|  1.44M|        this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
  202|  1.44M|        this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
  203|  1.44M|        this->check_utf8_bytes(input.chunks[3], input.chunks[2]);
  204|  1.44M|      }
  205|  1.44M|      this->prev_incomplete =
  206|  1.44M|          is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1]);
  207|  1.44M|      this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1];
  208|  1.44M|    }
  209|  1.66M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker16check_utf8_bytesENS1_4simd5simd8IhEES6_:
  169|  5.78M|                                              const simd8<uint8_t> prev_input) {
  170|       |    // Flip prev1...prev3 so we can easily determine if they are 2+, 3+ or 4+
  171|       |    // lead bytes (2, 3, 4-byte leads become large positive numbers instead of
  172|       |    // small negative numbers)
  173|  5.78M|    simd8<uint8_t> prev1 = input.prev<1>(prev_input);
  174|  5.78M|    simd8<uint8_t> sc = check_special_cases(input, prev1);
  175|  5.78M|    this->error |= check_multibyte_lengths(input, prev_input, sc);
  176|  5.78M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation19check_special_casesENS1_4simd5simd8IhEES5_:
    9|  5.78M|check_special_cases(const simd8<uint8_t> input, const simd8<uint8_t> prev1) {
   10|       |  // Bit 0 = Too Short (lead byte/ASCII followed by lead byte/ASCII)
   11|       |  // Bit 1 = Too Long (ASCII followed by continuation)
   12|       |  // Bit 2 = Overlong 3-byte
   13|       |  // Bit 4 = Surrogate
   14|       |  // Bit 5 = Overlong 2-byte
   15|       |  // Bit 7 = Two Continuations
   16|  5.78M|  constexpr const uint8_t TOO_SHORT = 1 << 0;  // 11______ 0_______
   17|       |                                               // 11______ 11______
   18|  5.78M|  constexpr const uint8_t TOO_LONG = 1 << 1;   // 0_______ 10______
   19|  5.78M|  constexpr const uint8_t OVERLONG_3 = 1 << 2; // 11100000 100_____
   20|  5.78M|  constexpr const uint8_t SURROGATE = 1 << 4;  // 11101101 101_____
   21|  5.78M|  constexpr const uint8_t OVERLONG_2 = 1 << 5; // 1100000_ 10______
   22|  5.78M|  constexpr const uint8_t TWO_CONTS = 1 << 7;  // 10______ 10______
   23|  5.78M|  constexpr const uint8_t TOO_LARGE = 1 << 3;  // 11110100 1001____
   24|       |                                               // 11110100 101_____
   25|       |                                               // 11110101 1001____
   26|       |                                               // 11110101 101_____
   27|       |                                               // 1111011_ 1001____
   28|       |                                               // 1111011_ 101_____
   29|       |                                               // 11111___ 1001____
   30|       |                                               // 11111___ 101_____
   31|  5.78M|  constexpr const uint8_t TOO_LARGE_1000 = 1 << 6;
   32|       |  // 11110101 1000____
   33|       |  // 1111011_ 1000____
   34|       |  // 11111___ 1000____
   35|  5.78M|  constexpr const uint8_t OVERLONG_4 = 1 << 6; // 11110000 1000____
   36|       |
   37|  5.78M|  const simd8<uint8_t> byte_1_high = prev1.shr<4>().lookup_16<uint8_t>(
   38|       |      // 0_______ ________ <ASCII in byte 1>
   39|  5.78M|      TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG,
   40|  5.78M|      TOO_LONG,
   41|       |      // 10______ ________ <continuation in byte 1>
   42|  5.78M|      TWO_CONTS, TWO_CONTS, TWO_CONTS, TWO_CONTS,
   43|       |      // 1100____ ________ <two byte lead in byte 1>
   44|  5.78M|      TOO_SHORT | OVERLONG_2,
   45|       |      // 1101____ ________ <two byte lead in byte 1>
   46|  5.78M|      TOO_SHORT,
   47|       |      // 1110____ ________ <three byte lead in byte 1>
   48|  5.78M|      TOO_SHORT | OVERLONG_3 | SURROGATE,
   49|       |      // 1111____ ________ <four+ byte lead in byte 1>
   50|  5.78M|      TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4);
   51|  5.78M|  constexpr const uint8_t CARRY =
   52|  5.78M|      TOO_SHORT | TOO_LONG | TWO_CONTS; // These all have ____ in byte 1 .
   53|  5.78M|  const simd8<uint8_t> byte_1_low =
   54|  5.78M|      (prev1 & 0x0F)
   55|  5.78M|          .lookup_16<uint8_t>(
   56|       |              // ____0000 ________
   57|  5.78M|              CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4,
   58|       |              // ____0001 ________
   59|  5.78M|              CARRY | OVERLONG_2,
   60|       |              // ____001_ ________
   61|  5.78M|              CARRY, CARRY,
   62|       |
   63|       |              // ____0100 ________
   64|  5.78M|              CARRY | TOO_LARGE,
   65|       |              // ____0101 ________
   66|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   67|       |              // ____011_ ________
   68|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   69|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   70|       |
   71|       |              // ____1___ ________
   72|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   73|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   74|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   75|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   76|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   77|       |              // ____1101 ________
   78|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE,
   79|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   80|  5.78M|              CARRY | TOO_LARGE | TOO_LARGE_1000);
   81|  5.78M|  const simd8<uint8_t> byte_2_high = input.shr<4>().lookup_16<uint8_t>(
   82|       |      // ________ 0_______ <ASCII in byte 2>
   83|  5.78M|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT,
   84|  5.78M|      TOO_SHORT, TOO_SHORT,
   85|       |
   86|       |      // ________ 1000____
   87|  5.78M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 |
   88|  5.78M|          OVERLONG_4,
   89|       |      // ________ 1001____
   90|  5.78M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE,
   91|       |      // ________ 101_____
   92|  5.78M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   93|  5.78M|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   94|       |
   95|       |      // ________ 11______
   96|  5.78M|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT);
   97|  5.78M|  return (byte_1_high & byte_1_low & byte_2_high);
   98|  5.78M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation23check_multibyte_lengthsENS1_4simd5simd8IhEES5_S5_:
  102|  5.78M|                        const simd8<uint8_t> sc) {
  103|  5.78M|  simd8<uint8_t> prev2 = input.prev<2>(prev_input);
  104|  5.78M|  simd8<uint8_t> prev3 = input.prev<3>(prev_input);
  105|  5.78M|  simd8<uint8_t> must23 =
  106|  5.78M|      simd8<uint8_t>(must_be_2_3_continuation(prev2, prev3));
  107|  5.78M|  simd8<uint8_t> must23_80 = must23 & uint8_t(0x80);
  108|  5.78M|  return must23_80 ^ sc;
  109|  5.78M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation13is_incompleteENS1_4simd5simd8IhEE:
  115|  1.44M|simdutf_really_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) {
  116|       |  // If the previous input's last 3 bytes match this, they're too short (they
  117|       |  // ended at EOF):
  118|       |  // ... 1111____ 111_____ 11______
  119|  1.44M|  static const uint8_t max_array[32] = {255,
  120|  1.44M|                                        255,
  121|  1.44M|                                        255,
  122|  1.44M|                                        255,
  123|  1.44M|                                        255,
  124|  1.44M|                                        255,
  125|  1.44M|                                        255,
  126|  1.44M|                                        255,
  127|  1.44M|                                        255,
  128|  1.44M|                                        255,
  129|  1.44M|                                        255,
  130|  1.44M|                                        255,
  131|  1.44M|                                        255,
  132|  1.44M|                                        255,
  133|  1.44M|                                        255,
  134|  1.44M|                                        255,
  135|  1.44M|                                        255,
  136|  1.44M|                                        255,
  137|  1.44M|                                        255,
  138|  1.44M|                                        255,
  139|  1.44M|                                        255,
  140|  1.44M|                                        255,
  141|  1.44M|                                        255,
  142|  1.44M|                                        255,
  143|  1.44M|                                        255,
  144|  1.44M|                                        255,
  145|  1.44M|                                        255,
  146|  1.44M|                                        255,
  147|  1.44M|                                        255,
  148|  1.44M|                                        0b11110000u - 1,
  149|  1.44M|                                        0b11100000u - 1,
  150|  1.44M|                                        0b11000000u - 1};
  151|  1.44M|  const simd8<uint8_t> max_value(
  152|  1.44M|      &max_array[sizeof(max_array) - sizeof(simd8<uint8_t>)]);
  153|  1.44M|  return input.gt_bits(max_value);
  154|  1.44M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker9check_eofEv:
  181|  2.23k|  simdutf_really_inline void check_eof() {
  182|       |    // If the previous block had incomplete UTF-8 characters at the end, an
  183|       |    // ASCII block can't possibly finish them.
  184|  2.23k|    this->error |= this->prev_incomplete;
  185|  2.23k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker6errorsEv:
  212|  2.23k|  simdutf_really_inline bool errors() const {
  213|  2.23k|    return this->error.any_bits_set_anywhere();
  214|  2.23k|  }

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation21generic_validate_utf8EPKcm:
   27|  2.23k|bool generic_validate_utf8(const char *input, size_t length) {
   28|  2.23k|  return generic_validate_utf8<utf8_checker>(
   29|  2.23k|      reinterpret_cast<const uint8_t *>(input), length);
   30|  2.23k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation21generic_validate_utf8INS2_12utf8_checkerEEEbPKhm:
   10|  2.23k|bool generic_validate_utf8(const uint8_t *input, size_t length) {
   11|  2.23k|  checker c{};
   12|  2.23k|  buf_block_reader<64> reader(input, length);
   13|  1.66M|  while (reader.has_full_block()) {
  ------------------
  |  Branch (13:10): [True: 1.65M, False: 2.23k]
  ------------------
   14|  1.65M|    simd::simd8x64<uint8_t> in(reader.full_block());
   15|  1.65M|    c.check_next_input(in);
   16|  1.65M|    reader.advance();
   17|  1.65M|  }
   18|  2.23k|  uint8_t block[64]{};
   19|  2.23k|  reader.get_remainder(block);
   20|  2.23k|  simd::simd8x64<uint8_t> in(block);
   21|  2.23k|  c.check_next_input(in);
   22|  2.23k|  reader.advance();
   23|  2.23k|  c.check_eof();
   24|  2.23k|  return !c.errors();
   25|  2.23k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation21generic_validate_utf8EPKcm:
   27|  2.23k|bool generic_validate_utf8(const char *input, size_t length) {
   28|  2.23k|  return generic_validate_utf8<utf8_checker>(
   29|  2.23k|      reinterpret_cast<const uint8_t *>(input), length);
   30|  2.23k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation21generic_validate_utf8INS2_12utf8_checkerEEEbPKhm:
   10|  2.23k|bool generic_validate_utf8(const uint8_t *input, size_t length) {
   11|  2.23k|  checker c{};
   12|  2.23k|  buf_block_reader<64> reader(input, length);
   13|  1.66M|  while (reader.has_full_block()) {
  ------------------
  |  Branch (13:10): [True: 1.65M, False: 2.23k]
  ------------------
   14|  1.65M|    simd::simd8x64<uint8_t> in(reader.full_block());
   15|  1.65M|    c.check_next_input(in);
   16|  1.65M|    reader.advance();
   17|  1.65M|  }
   18|  2.23k|  uint8_t block[64]{};
   19|  2.23k|  reader.get_remainder(block);
   20|  2.23k|  simd::simd8x64<uint8_t> in(block);
   21|  2.23k|  c.check_next_input(in);
   22|  2.23k|  reader.advance();
   23|  2.23k|  c.check_eof();
   24|  2.23k|  return !c.errors();
   25|  2.23k|}

_ZNK7simdutf7haswell14implementation13validate_utf8EPKcm:
  264|  2.23k|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
  265|  2.23k|  return haswell::utf8_validation::generic_validate_utf8(buf, len);
  266|  2.23k|}
_ZNK7simdutf7haswell14implementation24utf8_length_from_utf16leEPKDsm:
 1129|    374|    const char16_t *input, size_t length) const noexcept {
 1130|    374|  return utf16::utf8_length_from_utf16_bytemask<endianness::LITTLE>(input,
 1131|    374|                                                                    length);
 1132|    374|}
_ZNK7simdutf7haswell14implementation24utf8_length_from_utf16beEPKDsm:
 1135|    389|    const char16_t *input, size_t length) const noexcept {
 1136|    389|  return utf16::utf8_length_from_utf16_bytemask<endianness::BIG>(input, length);
 1137|    389|}
_ZNK7simdutf7haswell14implementation41utf8_length_from_utf16le_with_replacementEPKDsm:
 1159|  1.11k|    const char16_t *input, size_t length) const noexcept {
 1160|  1.11k|  return utf16::utf8_length_from_utf16_with_replacement<endianness::LITTLE>(
 1161|  1.11k|      input, length);
 1162|  1.11k|}
_ZNK7simdutf7haswell14implementation41utf8_length_from_utf16be_with_replacementEPKDsm:
 1166|  1.12k|    const char16_t *input, size_t length) const noexcept {
 1167|  1.12k|  return utf16::utf8_length_from_utf16_with_replacement<endianness::BIG>(
 1168|  1.12k|      input, length);
 1169|  1.12k|}
_ZNK7simdutf7haswell14implementation40convert_utf16le_to_utf8_with_replacementEPKDsmPc:
 1173|  1.11k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
 1174|  1.11k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::LITTLE>(
 1175|  1.11k|      input, length, utf8_buffer);
 1176|  1.11k|}
_ZNK7simdutf7haswell14implementation40convert_utf16be_to_utf8_with_replacementEPKDsmPc:
 1180|  1.12k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
 1181|  1.12k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::BIG>(
 1182|  1.12k|      input, length, utf8_buffer);
 1183|  1.12k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_18is_asciiERKNS1_4simd8simd8x64IhEE:
   13|  1.66M|simdutf_really_inline bool is_ascii(const simd8x64<uint8_t> &input) {
   14|  1.66M|  return input.reduce_or().is_ascii();
   15|  1.66M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_124must_be_2_3_continuationENS1_4simd5simd8IhEES4_:
   22|  2.89M|                         const simd8<uint8_t> prev3) {
   23|  2.89M|  simd8<uint8_t> is_third_byte =
   24|  2.89M|      prev2.saturating_sub(0xe0u - 0x80); // Only 111_____ will be > 0x80
   25|  2.89M|  simd8<uint8_t> is_fourth_byte =
   26|  2.89M|      prev3.saturating_sub(0xf0u - 0x80); // Only 1111____ will be > 0x80
   27|  2.89M|  return simd8<bool>(is_third_byte | is_fourth_byte);
   28|  2.89M|}

_ZNK7simdutf14implementation27supported_by_runtime_systemEv:
   65|      8|bool implementation::supported_by_runtime_system() const {
   66|      8|  uint32_t required_instruction_sets = this->required_instruction_sets();
   67|      8|  uint32_t supported_instruction_sets =
   68|      8|      internal::detect_supported_architectures();
   69|      8|  return ((supported_instruction_sets & required_instruction_sets) ==
   70|      8|          required_instruction_sets);
   71|      8|}
_ZNK7simdutf8internal29available_implementation_list5beginEv:
 1504|      1|available_implementation_list::begin() const noexcept {
 1505|      1|  return internal::get_available_implementation_pointers().begin();
 1506|      1|}
_ZNK7simdutf8internal29available_implementation_list3endEv:
 1508|      1|available_implementation_list::end() const noexcept {
 1509|      1|  return internal::get_available_implementation_pointers().end();
 1510|      1|}
_ZN7simdutf29get_available_implementationsEv:
 1559|      1|get_available_implementations() {
 1560|      1|#if !SIMDUTF_USE_STATIC_INITIALIZATION
 1561|      1|  static const internal::available_implementation_list
 1562|      1|      available_implementations_instance{};
 1563|      1|#endif
 1564|      1|  return available_implementations_instance;
 1565|      1|}
simdutf.cpp:_ZN7simdutf8internalL37get_available_implementation_pointersEv:
  934|      2|get_available_implementation_pointers() {
  935|      2|#if !SIMDUTF_USE_STATIC_INITIALIZATION
  936|      2|  static const std::initializer_list<const implementation *>
  937|      2|      available_implementation_pointers{
  938|      2|  #if SIMDUTF_IMPLEMENTATION_ICELAKE
  939|      2|          get_icelake_singleton(),
  940|      2|  #endif
  941|      2|  #if SIMDUTF_IMPLEMENTATION_HASWELL
  942|      2|          get_haswell_singleton(),
  943|      2|  #endif
  944|      2|  #if SIMDUTF_IMPLEMENTATION_WESTMERE
  945|      2|          get_westmere_singleton(),
  946|      2|  #endif
  947|       |  #if SIMDUTF_IMPLEMENTATION_ARM64
  948|       |          get_arm64_singleton(),
  949|       |  #endif
  950|       |  #if SIMDUTF_IMPLEMENTATION_PPC64
  951|       |          get_ppc64_singleton(),
  952|       |  #endif
  953|       |  #if SIMDUTF_IMPLEMENTATION_RVV
  954|       |          get_rvv_singleton(),
  955|       |  #endif
  956|       |  #if SIMDUTF_IMPLEMENTATION_LASX
  957|       |          get_lasx_singleton(),
  958|       |  #endif
  959|       |  #if SIMDUTF_IMPLEMENTATION_LSX
  960|       |          get_lsx_singleton(),
  961|       |  #endif
  962|      2|  #if SIMDUTF_IMPLEMENTATION_FALLBACK
  963|      2|          get_fallback_singleton(),
  964|      2|  #endif
  965|      2|      };
  966|      2|#endif
  967|      2|  return available_implementation_pointers;
  968|      2|}
simdutf.cpp:_ZN7simdutf8internalL21get_icelake_singletonEv:
  158|      1|static const icelake::implementation *get_icelake_singleton() {
  159|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  160|      1|  static const icelake::implementation icelake_singleton{};
  161|      1|  #endif
  162|      1|  return &icelake_singleton;
  163|      1|}
simdutf.cpp:_ZN7simdutf8internalL21get_haswell_singletonEv:
  169|      1|static const haswell::implementation *get_haswell_singleton() {
  170|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  171|      1|  static const haswell::implementation haswell_singleton{};
  172|      1|  #endif
  173|      1|  return &haswell_singleton;
  174|      1|}
simdutf.cpp:_ZN7simdutf8internalL22get_westmere_singletonEv:
  180|      1|static const westmere::implementation *get_westmere_singleton() {
  181|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  182|      1|  static const westmere::implementation westmere_singleton{};
  183|      1|  #endif
  184|      1|  return &westmere_singleton;
  185|      1|}
simdutf.cpp:_ZN7simdutf8internalL22get_fallback_singletonEv:
  246|      1|static const fallback::implementation *get_fallback_singleton() {
  247|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  248|      1|  static const fallback::implementation fallback_singleton{};
  249|      1|  #endif
  250|      1|  return &fallback_singleton;
  251|      1|}

_ZN7simdutf8fallback14implementationC2Ev:
   16|      1|      : simdutf::implementation("fallback", "Generic fallback implementation",
   17|      1|                                0) {}

_ZN7simdutf7haswell14implementationC2Ev:
   16|      1|      : simdutf::implementation("haswell", "Intel/AMD AVX2",
   17|      1|                                internal::instruction_set::AVX2 |
   18|      1|                                    internal::instruction_set::BMI1 |
   19|      1|                                    internal::instruction_set::BMI2) {}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2Ev:
  191|  6.70k|  simdutf_really_inline simd8() : base8_numeric<uint8_t>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhEC2Ev:
  124|  6.70k|  simdutf_really_inline base8_numeric() : base8<T>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2Ev:
   71|  6.70k|  simdutf_really_inline base8() : base<simd8<T>>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2Ev:
   14|  6.70k|  simdutf_really_inline base() : value{__m256i()} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd8simd8x64IhE9reduce_orEv:
  294|  1.66M|  simdutf_really_inline simd8<T> reduce_or() const {
  295|  1.66M|    return this->chunks[0] | this->chunks[1];
  296|  1.66M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEorES5_:
   50|  7.65M|  simdutf_really_inline Child operator|(const Child other) const {
   51|  7.65M|    return _mm256_or_si256(*this, other);
   52|  7.65M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2EDv4_x:
  193|  91.9M|      : base8_numeric<uint8_t>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhEC2EDv4_x:
  126|  91.9M|      : base8<T>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2EDv4_x:
   73|  91.9M|  simdutf_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2EDv4_x:
   17|  91.9M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE8is_asciiEv:
  234|  1.66M|  simdutf_really_inline bool is_ascii() const {
  235|  1.66M|    return _mm256_movemask_epi8(*this) == 0;
  236|  1.66M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEoRES5_:
   59|  3.10M|  simdutf_really_inline Child &operator|=(const Child other) {
   60|  3.10M|    auto this_cast = static_cast<Child *>(this);
   61|  3.10M|    *this_cast = *this_cast | other;
   62|  3.10M|    return *this_cast;
   63|  3.10M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi1EEENS4_IhEES8_:
   83|  2.89M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|  2.89M|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|  2.89M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE3shrILi4EEES4_v:
  245|  5.78M|  template <int N> simdutf_really_inline simd8<uint8_t> shr() const {
  246|  5.78M|    return simd8<uint8_t>(_mm256_srli_epi16(*this, N)) & uint8_t(0xFFu >> N);
  247|  5.78M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_:
  157|  8.67M|            L replace15) const {
  158|  8.67M|    return lookup_16(simd8<L>::repeat_16(
  159|  8.67M|        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
  160|  8.67M|        replace7, replace8, replace9, replace10, replace11, replace12,
  161|  8.67M|        replace13, replace14, replace15));
  162|  8.67M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES8_:
  148|  8.67M|  simdutf_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
  149|  8.67M|    return _mm256_shuffle_epi8(lookup_table, *this);
  150|  8.67M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE9repeat_16Ehhhhhhhhhhhhhhhh:
  118|  8.67M|                                                  T v14, T v15) {
  119|  8.67M|    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
  120|  8.67M|                    v14, v15, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  121|  8.67M|                    v12, v13, v14, v15);
  122|  8.67M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2Ehhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh:
  207|  8.67M|      : simd8(_mm256_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  208|  8.67M|                               v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
  209|  8.67M|                               v22, v23, v24, v25, v26, v27, v28, v29, v30,
  210|  8.67M|                               v31)) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2Eh:
  195|  17.3M|  simdutf_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi2EEENS4_IhEES8_:
   83|  2.89M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|  2.89M|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|  2.89M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi3EEENS4_IhEES8_:
   83|  2.89M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|  2.89M|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|  2.89M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE14saturating_subES4_:
  214|  7.22M|  saturating_sub(const simd8<uint8_t> other) const {
  215|  7.22M|    return _mm256_subs_epu8(*this, other);
  216|  7.22M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IbEC2EDv4_x:
   95|  2.89M|  simdutf_really_inline simd8(const __m256i _value) : base8<bool>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IbNS2_5simd8IbEEEC2EDv4_x:
   73|  2.89M|  simdutf_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEC2EDv4_x:
   17|  2.89M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEcvRKDv4_xEv:
   19|  2.89M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEeoES5_:
   56|  2.89M|  simdutf_really_inline Child operator^(const Child other) const {
   57|  2.89M|    return _mm256_xor_si256(*this, other);
   58|  2.89M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2EPKh:
  197|  1.44M|  simdutf_really_inline simd8(const uint8_t values[32]) : simd8(load(values)) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE4loadEPKh:
  111|  4.76M|  static simdutf_really_inline simd8<T> load(const T values[32]) {
  112|  4.76M|    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(values));
  113|  4.76M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE7gt_bitsES4_:
  225|  1.44M|  gt_bits(const simd8<uint8_t> other) const {
  226|  1.44M|    return this->saturating_sub(other);
  227|  1.44M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEC2EDv4_x:
   17|  61.8M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEcvRKDv4_xEv:
   19|  61.8M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE21any_bits_set_anywhereEv:
  241|  2.23k|  simdutf_really_inline bool any_bits_set_anywhere() const {
  242|  2.23k|    return !bits_not_set_anywhere();
  243|  2.23k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE21bits_not_set_anywhereEv:
  237|  2.23k|  simdutf_really_inline bool bits_not_set_anywhere() const {
  238|  2.23k|    return _mm256_testz_si256(*this, *this);
  239|  2.23k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEC2EDv4_x:
   17|  5.03M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEcvRKDv4_xEv:
   19|  7.94M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE5splatEh:
  105|  17.3M|  static simdutf_really_inline simd8<T> splat(T _value) {
  106|  17.3M|    return _mm256_set1_epi8(_value);
  107|  17.3M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEcvRKDv4_xEv:
   19|   123M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEanES5_:
   53|  17.3M|  simdutf_really_inline Child operator&(const Child other) const {
   54|  17.3M|    return _mm256_and_si256(*this, other);
   55|  17.3M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd8simd8x64IhEC2EPKh:
  274|  1.66M|      : chunks{simd8<T>::load(ptr),
  275|  1.66M|               simd8<T>::load(ptr + sizeof(simd8<T>) / sizeof(T))} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEanES5_:
   53|  12.7M|  simdutf_really_inline Child operator&(const Child other) const {
   54|  12.7M|    return _mm256_and_si256(*this, other);
   55|  12.7M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEeoES5_:
   56|   330k|  simdutf_really_inline Child operator^(const Child other) const {
   57|   330k|    return _mm256_xor_si256(*this, other);
   58|   330k|  }

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEC2EDv4_x:
   97|  61.8M|      : base16_numeric<uint16_t>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItEC2EDv4_x:
   73|  61.8M|      : base16<T>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6base16ItNS2_6simd16IbEEEC2EDv4_x:
   20|  61.8M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE4loadEPKt:
   66|  4.37M|  static simdutf_really_inline simd16<T> load(const T values[8]) {
   67|  4.37M|    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(values));
   68|  4.37M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE10swap_bytesEv:
  139|  1.97M|  simdutf_really_inline simd16<uint16_t> swap_bytes() const {
  140|  1.97M|    const __m256i swap = _mm256_setr_epi8(
  141|  1.97M|        1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17, 16, 19, 18,
  142|  1.97M|        21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30);
  143|  1.97M|    return _mm256_shuffle_epi8(*this, swap);
  144|  1.97M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE5splatEt:
   58|  17.4M|  static simdutf_really_inline simd16<T> splat(T _value) {
   59|  17.4M|    return _mm256_set1_epi16(_value);
   60|  17.4M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdeqENS2_6simd16ItEES4_:
   26|  4.70M|                                               const simd16<T> rhs) {
   27|  4.70M|    return _mm256_cmpeq_epi16(lhs, rhs);
   28|  4.70M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16IbEC2EDv4_x:
   45|  5.03M|  simdutf_really_inline simd16(const __m256i _value) : base16<bool>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6base16IbNS2_6simd16IbEEEC2EDv4_x:
   20|  5.03M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16IbE10to_bitmaskEv:
   50|  2.91M|  simdutf_really_inline bitmask_type to_bitmask() const {
   51|  2.91M|    return _mm256_movemask_epi8(*this);
   52|  2.91M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEC2Et:
  100|  17.4M|  simdutf_really_inline simd16(uint16_t _value) : simd16(splat(_value)) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE4zeroEv:
   62|  3.35k|  static simdutf_really_inline simd16<T> zero() {
   63|  3.35k|    return _mm256_setzero_si256();
   64|  3.35k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd3minENS2_6simd16ItEES4_:
  259|  8.41M|simd16<uint16_t> min(const simd16<uint16_t> a, simd16<uint16_t> b) {
  260|  8.41M|  return _mm256_min_epu16(a.value, b.value);
  261|  8.41M|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItEpLENS2_6simd16ItEE:
   87|  12.4M|  simdutf_really_inline simd16<T> &operator+=(const simd16<T> other) {
   88|  12.4M|    *this = *this + other;
   89|  12.4M|    return *static_cast<simd16<T> *>(this);
   90|  12.4M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItEplENS2_6simd16ItEE:
   84|  12.4M|  simdutf_really_inline simd16<T> operator+(const simd16<T> other) const {
   85|  12.4M|    return _mm256_add_epi16(*this, other);
   86|  12.4M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE3sumEv:
  170|  3.35k|  simdutf_really_inline uint64_t sum() const {
  171|  3.35k|    const auto lo_u16 = _mm256_and_si256(value, _mm256_set1_epi32(0x0000ffff));
  172|  3.35k|    const auto hi_u16 = _mm256_srli_epi32(value, 16);
  173|  3.35k|    const auto sum_u32 = _mm256_add_epi32(lo_u16, hi_u16);
  174|       |
  175|  3.35k|    const auto lo_u32 =
  176|  3.35k|        _mm256_and_si256(sum_u32, _mm256_set1_epi64x(0xffffffff));
  177|  3.35k|    const auto hi_u32 = _mm256_srli_epi64(sum_u32, 32);
  178|  3.35k|    const auto sum_u64 = _mm256_add_epi64(lo_u32, hi_u32);
  179|       |
  180|  3.35k|    return uint64_t(_mm256_extract_epi64(sum_u64, 0)) +
  181|  3.35k|           uint64_t(_mm256_extract_epi64(sum_u64, 1)) +
  182|  3.35k|           uint64_t(_mm256_extract_epi64(sum_u64, 2)) +
  183|       |           uint64_t(_mm256_extract_epi64(sum_u64, 3));
  184|  3.35k|  }

_ZN7simdutf7icelake14implementationC2Ev:
   16|      1|      : simdutf::implementation(
   17|      1|            "icelake",
   18|      1|            "Intel AVX512 (AVX-512BW, AVX-512CD, AVX-512VL, AVX-512VBMI2 "
   19|      1|            "extensions)",
   20|      1|            internal::instruction_set::AVX2 | internal::instruction_set::BMI1 |
   21|      1|                internal::instruction_set::BMI2 |
   22|      1|                internal::instruction_set::AVX512BW |
   23|      1|                internal::instruction_set::AVX512CD |
   24|      1|                internal::instruction_set::AVX512VL |
   25|      1|                internal::instruction_set::AVX512VBMI2 |
   26|      1|                internal::instruction_set::AVX512VPOPCNTDQ) {}

_ZN7simdutf8westmere14implementationC2Ev:
   18|      1|      : simdutf::implementation("westmere", "Intel/AMD SSE4.2",
   19|      1|                                internal::instruction_set::SSE42) {}

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Ev:
  183|  6.70k|  simdutf_really_inline simd8() : base8_numeric<uint8_t>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhEC2Ev:
  118|  6.70k|  simdutf_really_inline base8_numeric() : base8<T>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2Ev:
   68|  6.70k|  simdutf_really_inline base8() : base<simd8<T>>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2Ev:
   13|  6.70k|  simdutf_really_inline base() : value{__m128i()} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd8simd8x64IhE9reduce_orEv:
  290|  1.66M|  simdutf_really_inline simd8<T> reduce_or() const {
  291|  1.66M|    return (this->chunks[0] | this->chunks[1]) |
  292|  1.66M|           (this->chunks[2] | this->chunks[3]);
  293|  1.66M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEorES5_:
   42|  16.7M|  simdutf_really_inline Child operator|(const Child other) const {
   43|  16.7M|    return _mm_or_si128(*this, other);
   44|  16.7M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2EDv2_x:
  185|   182M|      : base8_numeric<uint8_t>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhEC2EDv2_x:
  120|   182M|      : base8<T>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2EDv2_x:
   69|   182M|  simdutf_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2EDv2_x:
   16|   182M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE8is_asciiEv:
  228|  1.66M|  simdutf_really_inline bool is_ascii() const {
  229|  1.66M|    return _mm_movemask_epi8(*this) == 0;
  230|  1.66M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEoRES5_:
   51|  5.99M|  simdutf_really_inline Child &operator|=(const Child other) {
   52|  5.99M|    auto this_cast = static_cast<Child *>(this);
   53|  5.99M|    *this_cast = *this_cast | other;
   54|  5.99M|    return *this_cast;
   55|  5.99M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi1EEENS4_IhEES8_:
   79|  5.78M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|  5.78M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE3shrILi4EEES4_v:
  238|  11.5M|  template <int N> simdutf_really_inline simd8<uint8_t> shr() const {
  239|  11.5M|    return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N);
  240|  11.5M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_:
  151|  17.3M|            L replace15) const {
  152|  17.3M|    return lookup_16(simd8<L>::repeat_16(
  153|  17.3M|        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
  154|  17.3M|        replace7, replace8, replace9, replace10, replace11, replace12,
  155|  17.3M|        replace13, replace14, replace15));
  156|  17.3M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES8_:
  142|  17.3M|  simdutf_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
  143|  17.3M|    return _mm_shuffle_epi8(lookup_table, *this);
  144|  17.3M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE9repeat_16Ehhhhhhhhhhhhhhhh:
  113|  17.3M|                                                  T v14, T v15) {
  114|  17.3M|    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
  115|  17.3M|                    v14, v15);
  116|  17.3M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Ehhhhhhhhhhhhhhhh:
  196|  17.3M|      : simd8(_mm_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  197|  17.3M|                            v12, v13, v14, v15)) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Eh:
  188|  34.6M|  simdutf_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi2EEENS4_IhEES8_:
   79|  5.78M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|  5.78M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi3EEENS4_IhEES8_:
   79|  5.78M|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|  5.78M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE14saturating_subES4_:
  201|  13.0M|  saturating_sub(const simd8<uint8_t> other) const {
  202|  13.0M|    return _mm_subs_epu8(*this, other);
  203|  13.0M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IbEC2EDv2_x:
   91|  5.78M|  simdutf_really_inline simd8(const __m128i _value) : base8<bool>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IbNS2_5simd8IbEEEC2EDv2_x:
   69|  5.78M|  simdutf_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEC2EDv2_x:
   16|  5.78M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEcvRKDv2_xEv:
   18|  5.78M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEeoES5_:
   48|  5.78M|  simdutf_really_inline Child operator^(const Child other) const {
   49|  5.78M|    return _mm_xor_si128(*this, other);
   50|  5.78M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2EPKh:
  190|  1.44M|  simdutf_really_inline simd8(const uint8_t *values) : simd8(load(values)) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE4loadEPKh:
  106|  8.08M|  static simdutf_really_inline simd8<T> load(const T values[16]) {
  107|  8.08M|    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
  108|  8.08M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE7gt_bitsES4_:
  212|  1.44M|  gt_bits(const simd8<uint8_t> other) const {
  213|  1.44M|    return this->saturating_sub(other);
  214|  1.44M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEC2EDv2_x:
   16|   122M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEcvRKDv2_xEv:
   18|   122M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE21any_bits_set_anywhereEv:
  235|  2.23k|  simdutf_really_inline bool any_bits_set_anywhere() const {
  236|  2.23k|    return !bits_not_set_anywhere();
  237|  2.23k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE21bits_not_set_anywhereEv:
  232|  2.23k|  simdutf_really_inline bool bits_not_set_anywhere() const {
  233|  2.23k|    return _mm_testz_si128(*this, *this);
  234|  2.23k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEC2EDv2_x:
   16|  9.64M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEcvRKDv2_xEv:
   18|  15.4M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE5splatEh:
  102|  34.6M|  static simdutf_really_inline simd8<T> splat(T _value) {
  103|  34.6M|    return _mm_set1_epi8(_value);
  104|  34.6M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEcvRKDv2_xEv:
   18|   228M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEanES5_:
   45|  34.6M|  simdutf_really_inline Child operator&(const Child other) const {
   46|  34.6M|    return _mm_and_si128(*this, other);
   47|  34.6M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd8simd8x64IhEC2EPKh:
  270|  1.66M|      : chunks{simd8<T>::load(ptr),
  271|  1.66M|               simd8<T>::load(ptr + sizeof(simd8<T>) / sizeof(T)),
  272|  1.66M|               simd8<T>::load(ptr + 2 * sizeof(simd8<T>) / sizeof(T)),
  273|  1.66M|               simd8<T>::load(ptr + 3 * sizeof(simd8<T>) / sizeof(T))} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEanES5_:
   45|  25.2M|  simdutf_really_inline Child operator&(const Child other) const {
   46|  25.2M|    return _mm_and_si128(*this, other);
   47|  25.2M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEeoES5_:
   48|   518k|  simdutf_really_inline Child operator^(const Child other) const {
   49|   518k|    return _mm_xor_si128(*this, other);
   50|   518k|  }

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEC2EDv2_x:
   79|   122M|      : base16_numeric<uint16_t>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItEC2EDv2_x:
   54|   122M|      : base16<T>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6base16ItNS2_6simd16IbEEEC2EDv2_x:
    8|   122M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE4loadEPKt:
   47|  8.60M|  static simdutf_really_inline simd16<T> load(const T values[8]) {
   48|  8.60M|    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
   49|  8.60M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE10swap_bytesEv:
  121|  3.88M|  simdutf_really_inline simd16<uint16_t> swap_bytes() const {
  122|  3.88M|    const __m128i swap =
  123|  3.88M|        _mm_setr_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
  124|  3.88M|    return _mm_shuffle_epi8(*this, swap);
  125|  3.88M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE5splatEt:
   41|  34.4M|  static simdutf_really_inline simd16<T> splat(T _value) {
   42|  34.4M|    return _mm_set1_epi16(_value);
   43|  34.4M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdeqENS2_6simd16ItEES4_:
   11|  9.12M|                                               const simd16<T> rhs) {
   12|  9.12M|    return _mm_cmpeq_epi16(lhs, rhs);
   13|  9.12M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16IbEC2EDv2_x:
   28|  9.64M|  simdutf_really_inline simd16(const __m128i _value) : base16<bool>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6base16IbNS2_6simd16IbEEEC2EDv2_x:
    8|  9.64M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16IbE10to_bitmaskEv:
   33|  5.82M|  simdutf_really_inline int to_bitmask() const {
   34|  5.82M|    return _mm_movemask_epi8(*this);
   35|  5.82M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEC2Et:
   82|  34.4M|  simdutf_really_inline simd16(uint16_t _value) : simd16(splat(_value)) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE4zeroEv:
   45|  4.65k|  static simdutf_really_inline simd16<T> zero() { return _mm_setzero_si128(); }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd3minENS2_6simd16ItEES4_:
  240|  16.6M|simd16<uint16_t> min(const simd16<uint16_t> a, simd16<uint16_t> b) {
  241|  16.6M|  return _mm_min_epu16(a.value, b.value);
  242|  16.6M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItEpLENS2_6simd16ItEE:
   68|  24.7M|  simdutf_really_inline simd16<T> &operator+=(const simd16<T> other) {
   69|  24.7M|    *this = *this + other;
   70|  24.7M|    return *static_cast<simd16<T> *>(this);
   71|  24.7M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItEplENS2_6simd16ItEE:
   65|  24.7M|  simdutf_really_inline simd16<T> operator+(const simd16<T> other) const {
   66|  24.7M|    return _mm_add_epi16(*this, other);
   67|  24.7M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE3sumEv:
  134|  4.65k|  simdutf_really_inline uint64_t sum() const {
  135|  4.65k|    const auto lo_u16 = _mm_and_si128(value, _mm_set1_epi32(0x0000ffff));
  136|  4.65k|    const auto hi_u16 = _mm_srli_epi32(value, 16);
  137|  4.65k|    const auto sum_u32 = _mm_add_epi32(lo_u16, hi_u16);
  138|       |
  139|  4.65k|    const auto lo_u32 = _mm_and_si128(sum_u32, _mm_set1_epi64x(0xffffffff));
  140|  4.65k|    const auto hi_u32 = _mm_srli_epi64(sum_u32, 32);
  141|  4.65k|    const auto sum_u64 = _mm_add_epi64(lo_u32, hi_u32);
  142|       |
  143|  4.65k|    return uint64_t(_mm_extract_epi64(sum_u64, 0)) +
  144|       |           uint64_t(_mm_extract_epi64(sum_u64, 1));
  145|  4.65k|  }

_ZNK7simdutf8westmere14implementation13validate_utf8EPKcm:
  297|  2.23k|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
  298|  2.23k|  return westmere::utf8_validation::generic_validate_utf8(buf, len);
  299|  2.23k|}
_ZNK7simdutf8westmere14implementation24utf8_length_from_utf16leEPKDsm:
 1156|    374|    const char16_t *input, size_t length) const noexcept {
 1157|    374|  return utf16::utf8_length_from_utf16_bytemask<endianness::LITTLE>(input,
 1158|    374|                                                                    length);
 1159|    374|}
_ZNK7simdutf8westmere14implementation24utf8_length_from_utf16beEPKDsm:
 1162|    389|    const char16_t *input, size_t length) const noexcept {
 1163|    389|  return utf16::utf8_length_from_utf16_bytemask<endianness::BIG>(input, length);
 1164|    389|}
_ZNK7simdutf8westmere14implementation41utf8_length_from_utf16le_with_replacementEPKDsm:
 1248|  1.11k|    const char16_t *input, size_t length) const noexcept {
 1249|  1.11k|  return utf16::utf8_length_from_utf16_with_replacement<endianness::LITTLE>(
 1250|  1.11k|      input, length);
 1251|  1.11k|}
_ZNK7simdutf8westmere14implementation41utf8_length_from_utf16be_with_replacementEPKDsm:
 1255|  1.12k|    const char16_t *input, size_t length) const noexcept {
 1256|  1.12k|  return utf16::utf8_length_from_utf16_with_replacement<endianness::BIG>(
 1257|  1.12k|      input, length);
 1258|  1.12k|}
_ZNK7simdutf8westmere14implementation40convert_utf16le_to_utf8_with_replacementEPKDsmPc:
 1262|  1.11k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
 1263|  1.11k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::LITTLE>(
 1264|  1.11k|      input, length, utf8_buffer);
 1265|  1.11k|}
_ZNK7simdutf8westmere14implementation40convert_utf16be_to_utf8_with_replacementEPKDsmPc:
 1269|  1.12k|    const char16_t *input, size_t length, char *utf8_buffer) const noexcept {
 1270|  1.12k|  return scalar::utf16_to_utf8::convert_with_replacement<endianness::BIG>(
 1271|  1.12k|      input, length, utf8_buffer);
 1272|  1.12k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_18is_asciiERKNS1_4simd8simd8x64IhEE:
   13|  1.66M|simdutf_really_inline bool is_ascii(const simd8x64<uint8_t> &input) {
   14|  1.66M|  return input.reduce_or().is_ascii();
   15|  1.66M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_124must_be_2_3_continuationENS1_4simd5simd8IhEES4_:
   22|  5.78M|                         const simd8<uint8_t> prev3) {
   23|  5.78M|  simd8<uint8_t> is_third_byte =
   24|  5.78M|      prev2.saturating_sub(0xe0u - 0x80); // Only 111_____ will be >= 0x80
   25|  5.78M|  simd8<uint8_t> is_fourth_byte =
   26|  5.78M|      prev3.saturating_sub(0xf0u - 0x80); // Only 1111____ will be >= 0x80
   27|  5.78M|  return simd8<bool>(is_third_byte | is_fourth_byte);
   28|  5.78M|}

