_Z29get_supported_implementationsv:
   26|  2.87k|get_supported_implementations() {
   27|  2.87k|  static const auto impl = []() -> auto {
   28|  2.87k|    std::vector<const simdutf::implementation*> ret;
   29|  2.87k|    for (auto e : simdutf::get_available_implementations()) {
   30|  2.87k|      std::cerr << "implementation " << e->name() << " is available? "
   31|  2.87k|                << e->supported_by_runtime_system() << '\n';
   32|  2.87k|      if (e->supported_by_runtime_system()) {
   33|  2.87k|        ret.push_back(e);
   34|  2.87k|      }
   35|  2.87k|    }
   36|  2.87k|    return ret;
   37|  2.87k|  }();
   38|  2.87k|  return {impl.data(), impl.size()};
   39|  2.87k|}
_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|    566|inline bool operator!=(const simdutf::result& a, const simdutf::result& b) {
   43|    566|  return a.count != b.count || a.error != b.error;
  ------------------
  |  Branch (43:10): [True: 0, False: 566]
  |  Branch (43:32): [True: 0, False: 566]
  ------------------
   44|    566|}
_ZN10FNV1A_hash6as_strIJNSt3__16vectorIDsNS1_9allocatorIDsEEEEEEENS1_12basic_stringIcNS1_11char_traitsIcEENS3_IcEEEEDpRKT_:
  100|    399|  template <typename... Data> static std::string as_str(const Data&... data) {
  101|    399|    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
  102|    399|    std::uint64_t h;
  103|       |    if constexpr (sizeof...(Data) > 1) {
  104|       |      const std::array hashes{fnv1ahash_impl(data)...};
  105|       |      const auto s = std::span(hashes);
  106|       |      h = fnv1ahash_impl(s);
  107|    399|    } else {
  108|    399|      h = fnv1ahash_impl(data...);
  109|    399|    }
  110|    399|    constexpr std::size_t expected_chars = 16;
  111|    399|    std::string ret(expected_chars, '0');
  112|    399|    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
  113|    399|    assert(c.ec == std::errc{});
  ------------------
  |  Branch (113:5): [True: 399, False: 0]
  ------------------
  114|    399|    auto nwritten = c.ptr - ret.data();
  115|    399|    assert(nwritten <= expected_chars);
  ------------------
  |  Branch (115:5): [True: 399, False: 0]
  ------------------
  116|    399|    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
  117|    399|    return ret;
  118|    399|  }
_ZN10FNV1A_hash14fnv1ahash_implIDsQ11is_hashableIT_EEEmRKNSt3__16vectorIS1_NS2_9allocatorIS1_EEEE:
   96|    399|  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
   97|    399|    return fnv1ahash_impl(std::span(data));
   98|    399|  }
_ZN10FNV1A_hash14fnv1ahash_implIKDsLm18446744073709551615EQaaaa11is_hashableIT_Entsr3stdE9is_same_vIS2_cEntsr3stdE9is_same_vIS2_hEEEmNSt3__14spanIS2_XT0_EEE:
   89|    399|  static constexpr std::uint64_t fnv1ahash_impl(std::span<Basic, N> data) {
   90|    399|    return fnv1ahash_impl({reinterpret_cast<const unsigned char*>(data.data()),
   91|    399|                           data.size_bytes()});
   92|    399|  }
_ZN10FNV1A_hash14fnv1ahash_implENSt3__14spanIKhLm18446744073709551615EEE:
   65|    399|  fnv1ahash_impl(std::span<const unsigned char> bytes) {
   66|    399|    auto hash = offset;
   67|       |
   68|  15.7M|    for (std::uint64_t byte : bytes) {
  ------------------
  |  Branch (68:29): [True: 15.7M, False: 399]
  ------------------
   69|  15.7M|      hash ^= byte;
   70|  15.7M|      hash *= prime;
   71|  15.7M|    }
   72|       |
   73|    399|    return hash;
   74|    399|  }

_Z10autodetectNSt3__14spanIKcLm18446744073709551615EEE:
    9|    687|void autodetect(std::span<const char> chardata) {
   10|    687|  std::vector<simdutf::encoding_type> results;
   11|    687|  const auto implementations = get_supported_implementations();
   12|  2.06k|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (12:44): [True: 2.06k, False: 687]
  ------------------
   13|  2.06k|    results.push_back(
   14|  2.06k|        impl->autodetect_encoding(chardata.data(), chardata.size()));
   15|  2.06k|  }
   16|    687|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   17|    687|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (17:7): [True: 0, False: 687]
  ------------------
   18|      0|    std::cerr << "output differs between implementations\n";
   19|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (19:29): [True: 0, False: 0]
  ------------------
   20|      0|      std::cerr << "implementation " << implementations[i] << " gave "
   21|      0|                << results.at(i) << '\n';
   22|      0|    }
   23|      0|    std::abort();
   24|      0|  }
   25|    687|}
_Z6detectNSt3__14spanIKcLm18446744073709551615EEE:
   27|    660|void detect(std::span<const char> chardata) {
   28|    660|  std::vector<int> results;
   29|    660|  const auto implementations = get_supported_implementations();
   30|  1.98k|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (30:44): [True: 1.98k, False: 660]
  ------------------
   31|  1.98k|    results.push_back(impl->detect_encodings(chardata.data(), chardata.size()));
   32|  1.98k|  }
   33|    660|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   34|    660|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (34:7): [True: 0, False: 660]
  ------------------
   35|      0|    std::cerr << "in detect_encodings(const char*, std::size_t):\n";
   36|      0|    std::cerr << "output differs between implementations\n";
   37|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (37:29): [True: 0, False: 0]
  ------------------
   38|      0|      std::cerr << "implementation " << implementations[i]->name() << " gave "
   39|      0|                << results.at(i) << '\n';
   40|      0|    }
   41|      0|    std::cerr << " std::vector<unsigned char> data{";
   42|      0|    for (unsigned char x : chardata) {
  ------------------
  |  Branch (42:26): [True: 0, False: 0]
  ------------------
   43|      0|      std::cerr << +x << ", ";
   44|      0|    };
   45|      0|    std::cerr << "};\n";
   46|      0|    std::abort();
   47|      0|  }
   48|    660|}
_Z14validate_asciiNSt3__14spanIKcLm18446744073709551615EEE:
   50|    201|void validate_ascii(std::span<const char> chardata) {
   51|       |  // use int, not bool to avoid vector<bool>
   52|    201|  std::vector<int> results;
   53|    201|  const auto implementations = get_supported_implementations();
   54|    603|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (54:44): [True: 603, False: 201]
  ------------------
   55|    603|    results.push_back(+impl->validate_ascii(chardata.data(), chardata.size()));
   56|    603|  }
   57|    201|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   58|    201|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (58:7): [True: 0, False: 201]
  ------------------
   59|      0|    std::cerr << "in validate_ascii(const char*, std::size_t):\n";
   60|      0|    std::cerr << "output differs between implementations\n";
   61|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (61:29): [True: 0, False: 0]
  ------------------
   62|      0|      std::cerr << "implementation " << implementations[i]->name() << " gave "
   63|      0|                << results.at(i) << '\n';
   64|      0|    }
   65|      0|    std::cerr << " std::vector<unsigned char> data{";
   66|      0|    for (unsigned char x : chardata) {
  ------------------
  |  Branch (66:26): [True: 0, False: 0]
  ------------------
   67|      0|      std::cerr << +x << ", ";
   68|      0|    };
   69|      0|    std::cerr << "};\n";
   70|      0|    std::abort();
   71|      0|  }
   72|    201|}
_Z23validate_ascii_with_errNSt3__14spanIKcLm18446744073709551615EEE:
   74|    283|void validate_ascii_with_err(std::span<const char> chardata) {
   75|       |  // use int, not bool to avoid vector<bool>
   76|    283|  std::vector<simdutf::result> results;
   77|    283|  const auto implementations = get_supported_implementations();
   78|    849|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (78:44): [True: 849, False: 283]
  ------------------
   79|    849|    results.push_back(
   80|    849|        impl->validate_ascii_with_errors(chardata.data(), chardata.size()));
   81|    849|  }
   82|    283|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   83|    283|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (83:7): [True: 0, False: 283]
  ------------------
   84|      0|    std::cerr << "in validate_ascii(const char*, std::size_t):\n";
   85|      0|    std::cerr << "output differs between implementations\n";
   86|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (86:29): [True: 0, False: 0]
  ------------------
   87|      0|      std::cerr << "implementation " << implementations[i]->name() << " gave "
   88|      0|                << results.at(i) << '\n';
   89|      0|    }
   90|      0|    std::cerr << " std::vector<unsigned char> data{";
   91|      0|    for (unsigned char x : chardata) {
  ------------------
  |  Branch (91:26): [True: 0, False: 0]
  ------------------
   92|      0|      std::cerr << +x << ", ";
   93|      0|    };
   94|      0|    std::cerr << "};\n";
   95|      0|    std::abort();
   96|      0|  }
   97|    283|}
_Z16utf16_endiannessNSt3__14spanIKDsLm18446744073709551615EEE:
   99|    133|void utf16_endianness(std::span<const char16_t> data) {
  100|    133|  std::vector<std::string> results;
  101|    133|  const auto implementations = get_supported_implementations();
  102|    399|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (102:44): [True: 399, False: 133]
  ------------------
  103|    399|    std::vector<char16_t> out(data.size());
  104|    399|    impl->change_endianness_utf16(data.data(), data.size(), out.data());
  105|    399|    results.push_back(FNV1A_hash::as_str(out));
  106|    399|  }
  107|    133|  auto neq = [](const auto& a, const auto& b) { return a != b; };
  108|    133|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (108:7): [True: 0, False: 133]
  ------------------
  109|      0|    std::cerr << "in utf16_endianness(const char*, std::size_t):\n";
  110|      0|    std::cerr << "output differs between implementations\n";
  111|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (111:29): [True: 0, False: 0]
  ------------------
  112|      0|      std::cerr << "implementation " << implementations[i]->name() << " gave "
  113|      0|                << results.at(i) << '\n';
  114|      0|    }
  115|      0|    std::cerr << " std::vector<char16_t> data{";
  116|      0|    for (int x : data) {
  ------------------
  |  Branch (116:16): [True: 0, False: 0]
  ------------------
  117|      0|      std::cerr << +x << ", ";
  118|      0|    };
  119|      0|    std::cerr << "};\n";
  120|      0|    std::abort();
  121|      0|  }
  122|    133|}
_Z23validate_utf16_as_asciiNSt3__14spanIKDsLm18446744073709551615EEE:
  126|    225|void validate_utf16_as_ascii(std::span<const char16_t> data) {
  127|    225|  const auto implementations = get_supported_implementations();
  128|       |  // use int, not bool to avoid vector<bool>
  129|    225|  std::vector<int> le_results, be_results;
  130|    225|  le_results.reserve(implementations.size());
  131|    225|  be_results.reserve(implementations.size());
  132|    675|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (132:44): [True: 675, False: 225]
  ------------------
  133|    675|    le_results.push_back(
  134|    675|        +impl->validate_utf16le_as_ascii(data.data(), data.size()));
  135|    675|    be_results.push_back(
  136|    675|        +impl->validate_utf16be_as_ascii(data.data(), data.size()));
  137|    675|  }
  138|    225|  auto neq = [](const auto& a, const auto& b) { return a != b; };
  139|    225|  if (std::ranges::adjacent_find(le_results, neq) != le_results.end()) {
  ------------------
  |  Branch (139:7): [True: 0, False: 225]
  ------------------
  140|      0|    std::cerr << "validate_utf16le_as_ascii: output differs between "
  141|      0|                 "implementations\n";
  142|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (142:29): [True: 0, False: 0]
  ------------------
  143|      0|      std::cerr << "  " << implementations[i]->name() << " gave "
  144|      0|                << le_results[i] << '\n';
  145|      0|    }
  146|      0|    std::abort();
  147|      0|  }
  148|    225|  if (std::ranges::adjacent_find(be_results, neq) != be_results.end()) {
  ------------------
  |  Branch (148:7): [True: 0, False: 225]
  ------------------
  149|      0|    std::cerr << "validate_utf16be_as_ascii: output differs between "
  150|      0|                 "implementations\n";
  151|      0|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (151:29): [True: 0, False: 0]
  ------------------
  152|      0|      std::cerr << "  " << implementations[i]->name() << " gave "
  153|      0|                << be_results[i] << '\n';
  154|      0|    }
  155|      0|    std::abort();
  156|      0|  }
  157|       |  // If LE validates as ASCII, it must also validate as UTF-16LE (ASCII is a
  158|       |  // subset).
  159|    225|  if (le_results[0]) {
  ------------------
  |  Branch (159:7): [True: 27, False: 198]
  ------------------
  160|     81|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (160:46): [True: 81, False: 27]
  ------------------
  161|     81|      if (!impl->validate_utf16le(data.data(), data.size())) {
  ------------------
  |  Branch (161:11): [True: 0, False: 81]
  ------------------
  162|      0|        std::cerr << "validate_utf16le_as_ascii returned true but "
  163|      0|                     "validate_utf16le returned false"
  164|      0|                  << " impl=" << impl->name() << "\n";
  165|      0|        std::abort();
  166|      0|      }
  167|     81|    }
  168|     27|  }
  169|       |  // Same for BE.
  170|    225|  if (be_results[0]) {
  ------------------
  |  Branch (170:7): [True: 24, False: 201]
  ------------------
  171|     72|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (171:46): [True: 72, False: 24]
  ------------------
  172|     72|      if (!impl->validate_utf16be(data.data(), data.size())) {
  ------------------
  |  Branch (172:11): [True: 0, False: 72]
  ------------------
  173|      0|        std::cerr << "validate_utf16be_as_ascii returned true but "
  174|      0|                     "validate_utf16be returned false"
  175|      0|                  << " impl=" << impl->name() << "\n";
  176|      0|        std::abort();
  177|      0|      }
  178|     72|    }
  179|     24|  }
  180|    225|}
_Z20to_well_formed_utf16NSt3__14spanIKDsLm18446744073709551615EEE:
  186|    687|void to_well_formed_utf16(std::span<const char16_t> data) {
  187|    687|  const auto implementations = get_supported_implementations();
  188|    687|  if (implementations.empty()) {
  ------------------
  |  Branch (188:7): [True: 0, False: 687]
  ------------------
  189|      0|    return;
  190|      0|  }
  191|       |
  192|       |  // Check LE variant
  193|    687|  {
  194|    687|    std::vector<std::vector<char16_t>> le_outputs;
  195|    687|    le_outputs.reserve(implementations.size());
  196|  2.06k|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (196:46): [True: 2.06k, False: 687]
  ------------------
  197|  2.06k|      std::vector<char16_t> out(data.size());
  198|  2.06k|      impl->to_well_formed_utf16le(data.data(), data.size(), out.data());
  199|  2.06k|      le_outputs.push_back(std::move(out));
  200|  2.06k|    }
  201|    687|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  202|    687|    if (std::ranges::adjacent_find(le_outputs, neq) != le_outputs.end()) {
  ------------------
  |  Branch (202:9): [True: 0, False: 687]
  ------------------
  203|      0|      std::cerr
  204|      0|          << "to_well_formed_utf16le: outputs differ between implementations\n";
  205|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (205:31): [True: 0, False: 0]
  ------------------
  206|      0|        std::cerr << "  " << implementations[i]->name()
  207|      0|                  << ": hash=" << FNV1A_hash::as_str(le_outputs[i]) << "\n";
  208|      0|      }
  209|      0|      std::abort();
  210|      0|    }
  211|       |    // Output must be valid UTF-16LE.
  212|  2.74k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (212:29): [True: 2.06k, False: 687]
  ------------------
  213|  2.06k|      if (!implementations[i]->validate_utf16le(le_outputs[i].data(),
  ------------------
  |  Branch (213:11): [True: 0, False: 2.06k]
  ------------------
  214|  2.06k|                                                le_outputs[i].size())) {
  215|      0|        std::cerr << "to_well_formed_utf16le: output is not valid UTF-16LE"
  216|      0|                  << " impl=" << implementations[i]->name() << "\n";
  217|      0|        std::abort();
  218|      0|      }
  219|  2.06k|    }
  220|       |    // If input was already valid UTF-16LE, output must equal input.
  221|    687|    if (implementations[0]->validate_utf16le(data.data(), data.size())) {
  ------------------
  |  Branch (221:9): [True: 211, False: 476]
  ------------------
  222|    211|      if (!std::ranges::equal(le_outputs[0], data)) {
  ------------------
  |  Branch (222:11): [True: 0, False: 211]
  ------------------
  223|      0|        std::cerr << "to_well_formed_utf16le: valid input was modified\n";
  224|      0|        std::abort();
  225|      0|      }
  226|    211|    }
  227|    687|  }
  228|       |
  229|       |  // Check BE variant
  230|    687|  {
  231|    687|    std::vector<std::vector<char16_t>> be_outputs;
  232|    687|    be_outputs.reserve(implementations.size());
  233|  2.06k|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (233:46): [True: 2.06k, False: 687]
  ------------------
  234|  2.06k|      std::vector<char16_t> out(data.size());
  235|  2.06k|      impl->to_well_formed_utf16be(data.data(), data.size(), out.data());
  236|  2.06k|      be_outputs.push_back(std::move(out));
  237|  2.06k|    }
  238|    687|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  239|    687|    if (std::ranges::adjacent_find(be_outputs, neq) != be_outputs.end()) {
  ------------------
  |  Branch (239:9): [True: 0, False: 687]
  ------------------
  240|      0|      std::cerr
  241|      0|          << "to_well_formed_utf16be: outputs differ between implementations\n";
  242|      0|      for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (242:31): [True: 0, False: 0]
  ------------------
  243|      0|        std::cerr << "  " << implementations[i]->name()
  244|      0|                  << ": hash=" << FNV1A_hash::as_str(be_outputs[i]) << "\n";
  245|      0|      }
  246|      0|      std::abort();
  247|      0|    }
  248|       |    // Output must be valid UTF-16BE.
  249|  2.74k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (249:29): [True: 2.06k, False: 687]
  ------------------
  250|  2.06k|      if (!implementations[i]->validate_utf16be(be_outputs[i].data(),
  ------------------
  |  Branch (250:11): [True: 0, False: 2.06k]
  ------------------
  251|  2.06k|                                                be_outputs[i].size())) {
  252|      0|        std::cerr << "to_well_formed_utf16be: output is not valid UTF-16BE"
  253|      0|                  << " impl=" << implementations[i]->name() << "\n";
  254|      0|        std::abort();
  255|      0|      }
  256|  2.06k|    }
  257|       |    // If input was already valid UTF-16BE, output must equal input.
  258|    687|    if (implementations[0]->validate_utf16be(data.data(), data.size())) {
  ------------------
  |  Branch (258:9): [True: 221, False: 466]
  ------------------
  259|    221|      if (!std::ranges::equal(be_outputs[0], data)) {
  ------------------
  |  Branch (259:11): [True: 0, False: 221]
  ------------------
  260|      0|        std::cerr << "to_well_formed_utf16be: valid input was modified\n";
  261|      0|        std::abort();
  262|      0|      }
  263|    221|    }
  264|    687|  }
  265|    687|}
_Z27convert_latin1_to_utf8_safeNSt3__14spanIKcLm18446744073709551615EEEm:
  268|    277|                                 const std::size_t outputsize) {
  269|       |  // convert with a limited output buffer
  270|    277|  std::vector<char> limited_output(outputsize);
  271|    277|  const auto limited_ret = simdutf::convert_latin1_to_utf8_safe(
  272|    277|      chardata.data(), chardata.size(), limited_output.data(), outputsize);
  273|       |
  274|       |  // convert with a sufficiently large output buffer
  275|    277|  std::vector<char> large_output(2 * chardata.size());
  276|    277|  const auto large_ret = simdutf::convert_latin1_to_utf8(
  277|    277|      chardata.data(), chardata.size(), large_output.data());
  278|       |
  279|    277|  if (large_ret != 0) {
  ------------------
  |  Branch (279:7): [True: 243, False: 34]
  ------------------
  280|       |    // conversion was possible with a large buffer.
  281|    243|    if (large_ret <= outputsize) {
  ------------------
  |  Branch (281:9): [True: 115, False: 128]
  ------------------
  282|       |      // the limited buffer was large enough, ensure we got the same result
  283|    115|      assert(limited_ret == large_ret);
  ------------------
  |  Branch (283:7): [True: 115, False: 0]
  ------------------
  284|    115|      assert(std::ranges::equal(limited_output | std::views::take(large_ret),
  ------------------
  |  Branch (284:7): [True: 115, False: 0]
  ------------------
  285|    115|                                large_output | std::views::take(large_ret)));
  286|    128|    } else {
  287|       |      // the number of written bytes for a limited buffer must not exceed what
  288|       |      // the large buffer got.
  289|    128|      assert(limited_ret <= large_ret);
  ------------------
  |  Branch (289:7): [True: 128, False: 0]
  ------------------
  290|       |      // the written data should be equal
  291|    128|      assert(std::ranges::equal(limited_output | std::views::take(limited_ret),
  ------------------
  |  Branch (291:7): [True: 128, False: 0]
  ------------------
  292|    128|                                large_output | std::views::take(limited_ret)));
  293|    128|    }
  294|    243|  } else {
  295|       |    // conversion with a big buffer failed - is there anything we can check or
  296|       |    // assert for the limited buffer? I don't think so.
  297|     34|  }
  298|    277|}
LLVMFuzzerTestOneInput:
  300|  3.29k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  301|       |  // pick one of the functions, based on the fuzz data.
  302|       |  // the first byte is which action to take. step forward
  303|       |  // several bytes so the input is aligned.
  304|  3.29k|  if (size < 4) {
  ------------------
  |  Branch (304:7): [True: 2, False: 3.29k]
  ------------------
  305|      2|    return 0;
  306|      2|  }
  307|  3.29k|  constexpr auto Ncases = 11u;
  308|  3.29k|  constexpr auto actionmask = std::bit_ceil(Ncases) - 1;
  309|  3.29k|  const auto action = data[0] & actionmask;
  310|       |
  311|  3.29k|  const std::uint16_t u16 = data[1] + (data[2] << 8);
  312|       |
  313|  3.29k|  data += 4;
  314|  3.29k|  size -= 4;
  315|       |
  316|  3.29k|  const std::span<const char> chardata{(const char*)data, size};
  317|  3.29k|  const std::span<const char16_t> u16data{(const char16_t*)data,
  318|  3.29k|                                          size / sizeof(char16_t)};
  319|       |
  320|  3.29k|  switch (action) {
  ------------------
  |  Branch (320:11): [True: 3.29k, False: 1]
  ------------------
  321|    687|  case 0:
  ------------------
  |  Branch (321:3): [True: 687, False: 2.60k]
  ------------------
  322|    687|    autodetect(chardata);
  323|    687|    break;
  324|    660|  case 1:
  ------------------
  |  Branch (324:3): [True: 660, False: 2.63k]
  ------------------
  325|    660|    detect(chardata);
  326|    660|    break;
  327|    201|  case 2:
  ------------------
  |  Branch (327:3): [True: 201, False: 3.09k]
  ------------------
  328|    201|    validate_ascii(chardata);
  329|    201|    break;
  330|    283|  case 3:
  ------------------
  |  Branch (330:3): [True: 283, False: 3.01k]
  ------------------
  331|    283|    validate_ascii_with_err(chardata);
  332|    283|    break;
  333|    133|  case 4:
  ------------------
  |  Branch (333:3): [True: 133, False: 3.16k]
  ------------------
  334|    133|    utf16_endianness(u16data);
  335|    133|    break;
  336|     33|  case 5: {
  ------------------
  |  Branch (336:3): [True: 33, False: 3.26k]
  ------------------
  337|     33|    [[maybe_unused]] auto ret =
  338|     33|        simdutf::trim_partial_utf16le(u16data.data(), u16data.size());
  339|     33|    assert(ret == u16data.size() || ret + 1 == u16data.size());
  ------------------
  |  Branch (339:5): [True: 21, False: 12]
  |  Branch (339:5): [True: 12, False: 0]
  |  Branch (339:5): [True: 33, False: 0]
  ------------------
  340|     33|  } break;
  341|     33|  case 6: {
  ------------------
  |  Branch (341:3): [True: 21, False: 3.27k]
  ------------------
  342|     21|    [[maybe_unused]] auto ret =
  343|     21|        simdutf::trim_partial_utf16be(u16data.data(), u16data.size());
  344|     21|    assert(ret == u16data.size() || ret + 1 == u16data.size());
  ------------------
  |  Branch (344:5): [True: 16, False: 5]
  |  Branch (344:5): [True: 5, False: 0]
  |  Branch (344:5): [True: 21, False: 0]
  ------------------
  345|     21|  } break;
  346|     88|  case 7: {
  ------------------
  |  Branch (346:3): [True: 88, False: 3.20k]
  ------------------
  347|     88|    [[maybe_unused]] const std::size_t N = chardata.size();
  348|     88|    [[maybe_unused]] const auto ret =
  349|     88|        simdutf::trim_partial_utf8(chardata.data(), chardata.size());
  350|     88|    if ((ret + 3 < N) || (ret > N)) {
  ------------------
  |  Branch (350:9): [True: 0, False: 88]
  |  Branch (350:26): [True: 0, False: 88]
  ------------------
  351|      0|      std::cerr << "ret=" << ret << " N=" << N << '\n';
  352|      0|      std::abort();
  353|      0|    }
  354|     88|  } break;
  355|    277|  case 8:
  ------------------
  |  Branch (355:3): [True: 277, False: 3.01k]
  ------------------
  356|    277|    convert_latin1_to_utf8_safe(chardata, u16);
  357|    277|    break;
  358|    225|  case 9:
  ------------------
  |  Branch (358:3): [True: 225, False: 3.07k]
  ------------------
  359|    225|    validate_utf16_as_ascii(u16data);
  360|    225|    break;
  361|    687|  case 10:
  ------------------
  |  Branch (361:3): [True: 687, False: 2.60k]
  ------------------
  362|    687|    to_well_formed_utf16(u16data);
  363|    687|    break;
  364|  3.29k|  }
  365|  3.29k|  return 0;
  366|  3.29k|}
misc.cpp:_ZZ10autodetectNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIN7simdutf13encoding_typeES6_EEDaRKT_RKT0_:
   16|  1.37k|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ6detectNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
   33|  1.32k|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ14validate_asciiNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
   57|    402|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ23validate_ascii_with_errNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIN7simdutf6resultES6_EEDaRKT_RKT0_:
   82|    566|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ16utf16_endiannessNSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESA_EEDaRKT_RKT0_:
  107|    266|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ23validate_utf16_as_asciiNSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
  138|    900|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ20to_well_formed_utf16NSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clINS_6vectorIDsNS_9allocatorIDsEEEES8_EEDaRKT_RKT0_:
  201|  1.37k|    auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ20to_well_formed_utf16NSt3__14spanIKDsLm18446744073709551615EEEENK3$_1clINS_6vectorIDsNS_9allocatorIDsEEEES8_EEDaRKT_RKT0_:
  238|  1.37k|    auto neq = [](const auto& a, const auto& b) { return a != b; };

_ZN7simdutf6resultC2ENS_10error_codeEm:
   87|  7.26k|      : error{err}, count{pos} {}
_ZNK7simdutf6result6is_errEv:
   93|  5.02k|  simdutf_really_inline simdutf_constexpr23 bool is_err() const noexcept {
   94|  5.02k|    return error != error_code::SUCCESS;
   95|  5.02k|  }

_ZNK7simdutf14implementation4nameEv:
 5106|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5157|     10|  virtual uint32_t required_instruction_sets() const {
 5158|     10|    return _required_instruction_sets;
 5159|     10|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7043|      5|      : _name(name), _description(description),
 7044|      5|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7075|      1|  simdutf_really_inline available_implementation_list() {}
simdutf.cpp:_ZN7simdutf6detail12_GLOBAL__N_13minEmm:
   59|    552|constexpr std::size_t min(std::size_t a, std::size_t b) {
   60|    552|  return a < b ? a : b;
  ------------------
  |  Branch (60:10): [True: 167, False: 385]
  ------------------
   61|    552|}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEaSEPS3_:
 7146|      1|  atomic_ptr &operator=(T *_ptr) {
 7147|      1|    ptr = _ptr;
 7148|      1|    return *this;
 7149|      1|  }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEcvPS3_Ev:
 7143|      1|  operator T *() { return ptr.load(); }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEC2EPS3_:
 7123|      1|  atomic_ptr(T *_ptr) : ptr{_ptr} {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEptEv:
 7145|    552|  T *operator->() { return ptr.load(); }

simdutf.cpp:_ZN7simdutf8internalL30detect_supported_architecturesEv:
  236|      9|static inline uint32_t detect_supported_architectures() {
  237|      9|  uint32_t eax;
  238|      9|  uint32_t ebx = 0;
  239|      9|  uint32_t ecx = 0;
  240|      9|  uint32_t edx = 0;
  241|      9|  uint32_t host_isa = 0x0;
  242|       |
  243|       |  // EBX for EAX=0x1
  244|      9|  eax = 0x1;
  245|      9|  cpuid(&eax, &ebx, &ecx, &edx);
  246|       |
  247|      9|  if (ecx & cpuid_bit::sse42) {
  ------------------
  |  Branch (247:7): [True: 9, False: 0]
  ------------------
  248|      9|    host_isa |= instruction_set::SSE42;
  249|      9|  }
  250|       |
  251|      9|  if (ecx & cpuid_bit::pclmulqdq) {
  ------------------
  |  Branch (251:7): [True: 9, False: 0]
  ------------------
  252|      9|    host_isa |= instruction_set::PCLMULQDQ;
  253|      9|  }
  254|       |
  255|      9|  if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) {
  ------------------
  |  Branch (255:7): [True: 0, False: 9]
  ------------------
  256|      0|    return host_isa;
  257|      0|  }
  258|       |
  259|       |  // xgetbv for checking if the OS saves registers
  260|      9|  uint64_t xcr0 = xgetbv();
  261|       |
  262|      9|  if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) {
  ------------------
  |  Branch (262:7): [True: 0, False: 9]
  ------------------
  263|      0|    return host_isa;
  264|      0|  }
  265|       |  // ECX for EAX=0x7
  266|      9|  eax = 0x7;
  267|      9|  ecx = 0x0; // Sub-leaf = 0
  268|      9|  cpuid(&eax, &ebx, &ecx, &edx);
  269|      9|  if (ebx & cpuid_bit::ebx::avx2) {
  ------------------
  |  Branch (269:7): [True: 9, False: 0]
  ------------------
  270|      9|    host_isa |= instruction_set::AVX2;
  271|      9|  }
  272|      9|  if (ebx & cpuid_bit::ebx::bmi1) {
  ------------------
  |  Branch (272:7): [True: 9, False: 0]
  ------------------
  273|      9|    host_isa |= instruction_set::BMI1;
  274|      9|  }
  275|      9|  if (ebx & cpuid_bit::ebx::bmi2) {
  ------------------
  |  Branch (275:7): [True: 9, False: 0]
  ------------------
  276|      9|    host_isa |= instruction_set::BMI2;
  277|      9|  }
  278|      9|  if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) ==
  ------------------
  |  Branch (278:7): [True: 9, False: 0]
  ------------------
  279|      9|        cpuid_bit::xcr0_bit::avx512_saved)) {
  280|      9|    return host_isa;
  281|      9|  }
  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|      9|}
simdutf.cpp:_ZN7simdutf8internalL5cpuidEPjS1_S1_S1_:
  202|     18|                         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|     18|  uint32_t a = *eax, b, c = *ecx, d;
  216|     18|  asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d));
  217|     18|  *eax = a;
  218|     18|  *ebx = b;
  219|     18|  *ecx = c;
  220|     18|  *edx = d;
  221|     18|  #endif
  222|     18|}
simdutf.cpp:_ZN7simdutf8internalL6xgetbvEv:
  224|      9|static inline uint64_t xgetbv() {
  225|       |  #if defined(_MSC_VER)
  226|       |  return _xgetbv(0);
  227|       |  #elif defined(__FILC__)
  228|       |  return zxgetbv();
  229|       |  #else
  230|      9|  uint32_t xcr0_lo, xcr0_hi;
  231|      9|  asm volatile("xgetbv\n\t" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0));
  232|      9|  return xcr0_lo | ((uint64_t)xcr0_hi << 32);
  233|      9|  #endif
  234|      9|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_15ascii8validateIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEEbS6_m:
   16|    201|                                                      size_t len) noexcept {
   17|    201|  uint64_t pos = 0;
   18|       |
   19|       |#if SIMDUTF_CPLUSPLUS23
   20|       |  // avoid memcpy during constant evaluation
   21|       |  if !consteval
   22|       |#endif
   23|       |  // process in blocks of 16 bytes when possible
   24|    201|  {
   25|   174k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (25:12): [True: 174k, False: 79]
  ------------------
   26|   174k|      uint64_t v1;
   27|   174k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   28|   174k|      uint64_t v2;
   29|   174k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   30|   174k|      uint64_t v{v1 | v2};
   31|   174k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (31:11): [True: 122, False: 174k]
  ------------------
   32|    122|        return false;
   33|    122|      }
   34|   174k|    }
   35|    201|  }
   36|       |
   37|       |  // process the tail byte-by-byte
   38|    432|  for (; pos < len; pos++) {
  ------------------
  |  Branch (38:10): [True: 383, False: 49]
  ------------------
   39|    383|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (39:9): [True: 30, False: 353]
  ------------------
   40|     30|      return false;
   41|     30|    }
   42|    383|  }
   43|     49|  return true;
   44|     79|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_15ascii20validate_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_m:
   50|    775|validate_with_errors(InputPtr data, size_t len) noexcept {
   51|    775|  size_t pos = 0;
   52|       |#if SIMDUTF_CPLUSPLUS23
   53|       |  // avoid memcpy during constant evaluation
   54|       |  if !consteval
   55|       |#endif
   56|    775|  {
   57|       |    // process in blocks of 16 bytes when possible
   58|   207k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (58:12): [True: 207k, False: 166]
  ------------------
   59|   207k|      uint64_t v1;
   60|   207k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   61|   207k|      uint64_t v2;
   62|   207k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   63|   207k|      uint64_t v{v1 | v2};
   64|   207k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (64:11): [True: 609, False: 206k]
  ------------------
   65|  3.29k|        for (; pos < len; pos++) {
  ------------------
  |  Branch (65:16): [True: 3.29k, False: 0]
  ------------------
   66|  3.29k|          if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (66:15): [True: 609, False: 2.68k]
  ------------------
   67|    609|            return result(error_code::TOO_LARGE, pos);
   68|    609|          }
   69|  3.29k|        }
   70|    609|      }
   71|   207k|    }
   72|    775|  }
   73|       |
   74|       |  // process the tail byte-by-byte
   75|    630|  for (; pos < len; pos++) {
  ------------------
  |  Branch (75:10): [True: 593, False: 37]
  ------------------
   76|    593|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (76:9): [True: 129, False: 464]
  ------------------
   77|    129|      return result(error_code::TOO_LARGE, pos);
   78|    129|    }
   79|    593|  }
   80|     37|  return result(error_code::SUCCESS, pos);
   81|    166|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf812convert_safeEPKcmPcm:
   72|    277|                           size_t utf8_len) {
   73|    277|  const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   74|    277|  size_t pos = 0;
   75|    277|  size_t skip_pos = 0;
   76|    277|  size_t utf8_pos = 0;
   77|  1.59k|  while (pos < len && utf8_pos < utf8_len) {
  ------------------
  |  Branch (77:10): [True: 1.44k, False: 149]
  |  Branch (77:23): [True: 1.35k, False: 93]
  ------------------
   78|       |    // try to convert the next block of 16 ASCII bytes
   79|  1.35k|    if (pos >= skip_pos && pos + 16 <= len &&
  ------------------
  |  Branch (79:9): [True: 779, False: 573]
  |  Branch (79:28): [True: 451, False: 328]
  ------------------
   80|    451|        utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes,
  ------------------
  |  Branch (80:9): [True: 65, False: 386]
  ------------------
   81|       |                                     // check that they are ascii
   82|     65|      uint64_t v1;
   83|     65|      ::memcpy(&v1, data + pos, sizeof(uint64_t));
   84|     65|      uint64_t v2;
   85|     65|      ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   86|     65|      uint64_t v{v1 |
   87|     65|                 v2}; // We are only interested in these bits: 1000 1000 1000
   88|       |                      // 1000, so it makes sense to concatenate everything
   89|     65|      if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (89:11): [True: 27, False: 38]
  ------------------
   90|     65|          0) { // if NONE of these are set, e.g. all of them are zero, then
   91|       |               // everything is ASCII
   92|     27|        ::memcpy(utf8_output + utf8_pos, buf + pos, 16);
   93|     27|        utf8_pos += 16;
   94|     27|        pos += 16;
   95|     38|      } else {
   96|       |        // At least one of the next 16 bytes are not ASCII, we will process them
   97|       |        // one by one
   98|     38|        skip_pos = pos + 16;
   99|     38|      }
  100|  1.28k|    } else {
  101|  1.28k|      const auto byte = data[pos];
  102|  1.28k|      if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (102:11): [True: 838, False: 449]
  ------------------
  103|       |        // will generate one UTF-8 bytes
  104|    838|        utf8_output[utf8_pos++] = char(byte);
  105|    838|        pos++;
  106|    838|      } else if (utf8_pos + 2 <= utf8_len) {
  ------------------
  |  Branch (106:18): [True: 414, False: 35]
  ------------------
  107|       |        // will generate two UTF-8 bytes
  108|    414|        utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
  109|    414|        utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
  110|    414|        pos++;
  111|    414|      } else {
  112|     35|        break;
  113|     35|      }
  114|  1.28k|    }
  115|  1.35k|  }
  116|    277|  return utf8_pos;
  117|    277|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertEPKcmPc:
   66|    518|                                     char *utf8_output) {
   67|    518|  return convert(reinterpret_cast<const unsigned char *>(buf), len,
   68|    518|                 utf8_output);
   69|    518|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_:
   17|    518|                                   OutputPtr utf8_output) {
   18|       |  // const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   19|    518|  size_t pos = 0;
   20|    518|  size_t utf8_pos = 0;
   21|       |
   22|  7.42k|  while (pos < len) {
  ------------------
  |  Branch (22:10): [True: 6.90k, False: 518]
  ------------------
   23|       |#if SIMDUTF_CPLUSPLUS23
   24|       |    if !consteval
   25|       |#endif
   26|  6.90k|    {
   27|       |      // try to convert the next block of 16 ASCII bytes
   28|  6.90k|      if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that
  ------------------
  |  Branch (28:11): [True: 1.22k, False: 5.68k]
  ------------------
   29|       |                             // they are ascii
   30|  1.22k|        uint64_t v1;
   31|  1.22k|        ::memcpy(&v1, data + pos, sizeof(uint64_t));
   32|  1.22k|        uint64_t v2;
   33|  1.22k|        ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   34|  1.22k|        uint64_t v{v1 |
   35|  1.22k|                   v2}; // We are only interested in these bits: 1000 1000 1000
   36|       |                        // 1000, so it makes sense to concatenate everything
   37|  1.22k|        if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (37:13): [True: 107, False: 1.11k]
  ------------------
   38|  1.22k|            0) { // if NONE of these are set, e.g. all of them are zero, then
   39|       |                 // everything is ASCII
   40|    107|          size_t final_pos = pos + 16;
   41|  1.81k|          while (pos < final_pos) {
  ------------------
  |  Branch (41:18): [True: 1.71k, False: 107]
  ------------------
   42|  1.71k|            utf8_output[utf8_pos++] = char(data[pos]);
   43|  1.71k|            pos++;
   44|  1.71k|          }
   45|    107|          continue;
   46|    107|        }
   47|  1.22k|      } // if (pos + 16 <= len)
   48|  6.90k|    } // !consteval scope
   49|       |
   50|  6.79k|    unsigned char byte = data[pos];
   51|  6.79k|    if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (51:9): [True: 2.98k, False: 3.80k]
  ------------------
   52|       |      // will generate one UTF-8 bytes
   53|  2.98k|      utf8_output[utf8_pos++] = char(byte);
   54|  2.98k|      pos++;
   55|  3.80k|    } else {
   56|       |      // will generate two UTF-8 bytes
   57|  3.80k|      utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
   58|  3.80k|      utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
   59|  3.80k|      pos++;
   60|  3.80k|    }
   61|  6.79k|  } // while
   62|    518|  return utf8_pos;
   63|    518|}

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

_ZN7simdutf6scalar5utf1623change_endianness_utf16EPKDsmPDs:
  119|    399|change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) {
  120|  2.62M|  for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (120:22): [True: 2.62M, False: 399]
  ------------------
  121|  2.62M|    *output++ = char16_t(input[i] >> 8 | input[i] << 8);
  122|  2.62M|  }
  123|    399|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE1EEEmPKDsm:
  127|     21|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     21|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 20]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     20|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     20|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     20|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     20|  return length;
  135|     21|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE0EEEmPKDsm:
  127|     33|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     33|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 32]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     32|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     32|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     32|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     32|  return length;
  135|     33|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE0EEEbPKDsm:
   10|    225|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  18.3k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 18.3k, False: 27]
  ------------------
   12|  18.3k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  18.3k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 198, False: 18.1k]
  ------------------
   14|    198|      return false;
   15|    198|    }
   16|  18.3k|  }
   17|     27|  return true;
   18|    225|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE1EEEbPKDsm:
   10|    225|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  16.9k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 16.9k, False: 24]
  ------------------
   12|  16.9k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  16.9k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 201, False: 16.7k]
  ------------------
   14|    201|      return false;
   15|    201|    }
   16|  16.9k|  }
   17|     24|  return true;
   18|    225|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE0EEEbPKDsm:
   22|  4.07k|validate(const char16_t *data, size_t len) noexcept {
   23|  4.07k|  uint64_t pos = 0;
   24|  14.7M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 14.7M, False: 2.90k]
  ------------------
   25|  14.7M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  14.7M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 27.1k, False: 14.7M]
  ------------------
   27|  27.1k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 206, False: 26.9k]
  ------------------
   28|    206|        return false;
   29|    206|      }
   30|  26.9k|      char16_t diff = char16_t(word - 0xD800);
   31|  26.9k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 456, False: 26.4k]
  ------------------
   32|    456|        return false;
   33|    456|      }
   34|  26.4k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [Folded, False: 26.4k]
  ------------------
   35|  26.4k|                               ? u16_swap_bytes(data[pos + 1])
   36|  26.4k|                               : data[pos + 1];
   37|  26.4k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  26.4k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 505, False: 25.9k]
  ------------------
   39|    505|        return false;
   40|    505|      }
   41|  25.9k|      pos += 2;
   42|  14.7M|    } else {
   43|  14.7M|      pos++;
   44|  14.7M|    }
   45|  14.7M|  }
   46|  2.90k|  return true;
   47|  4.07k|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE1EEEbPKDsm:
   22|  2.61k|validate(const char16_t *data, size_t len) noexcept {
   23|  2.61k|  uint64_t pos = 0;
   24|  8.28M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 8.27M, False: 2.34k]
  ------------------
   25|  8.27M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  8.27M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 25.9k, False: 8.25M]
  ------------------
   27|  25.9k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 43, False: 25.9k]
  ------------------
   28|     43|        return false;
   29|     43|      }
   30|  25.9k|      char16_t diff = char16_t(word - 0xD800);
   31|  25.9k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 102, False: 25.8k]
  ------------------
   32|    102|        return false;
   33|    102|      }
   34|  25.8k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [True: 25.8k, Folded]
  ------------------
   35|  25.8k|                               ? u16_swap_bytes(data[pos + 1])
   36|  25.8k|                               : data[pos + 1];
   37|  25.8k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  25.8k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 122, False: 25.7k]
  ------------------
   39|    122|        return false;
   40|    122|      }
   41|  25.7k|      pos += 2;
   42|  8.25M|    } else {
   43|  8.25M|      pos++;
   44|  8.25M|    }
   45|  8.27M|  }
   46|  2.34k|  return true;
   47|  2.61k|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE0EEEvPKDsmPDs:
  190|  1.00k|                                              char16_t *output) {
  191|  1.00k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.00k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.00k|  size_t i = 0;
  194|  8.26M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.26M, False: 1.00k]
  ------------------
  195|  8.26M|    char16_t c = input[i];
  196|  8.26M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.26M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.26M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 50.9k, False: 8.21M]
  |  Branch (198:32): [True: 28.1k, False: 22.8k]
  ------------------
  199|  28.1k|      output[i - 1] = replacement;
  200|  28.1k|    }
  201|       |
  202|  8.26M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.21M, False: 50.9k]
  |  Branch (202:33): [True: 269k, False: 7.94M]
  ------------------
  203|   269k|      output[i] = replacement;
  204|  7.99M|    } else {
  205|  7.99M|      output[i] = input[i];
  206|  7.99M|    }
  207|  8.26M|    high_surrogate_prev = high_surrogate;
  208|  8.26M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.00k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 139, False: 866]
  ------------------
  212|    139|    output[i - 1] = replacement;
  213|    139|  }
  214|  1.00k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  8.26M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.26M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.26M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 640k, False: 7.62M]
  |  Branch (139:26): [True: 51.2k, False: 589k]
  ------------------
  140|  8.26M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  8.26M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.26M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.26M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 589k, False: 7.67M]
  |  Branch (144:26): [True: 292k, False: 296k]
  ------------------
  145|  8.26M|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE1EEEvPKDsmPDs:
  190|  1.00k|                                              char16_t *output) {
  191|  1.00k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.00k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.00k|  size_t i = 0;
  194|  8.26M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.26M, False: 1.00k]
  ------------------
  195|  8.26M|    char16_t c = input[i];
  196|  8.26M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.26M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.26M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 52.5k, False: 8.21M]
  |  Branch (198:32): [True: 28.1k, False: 24.3k]
  ------------------
  199|  28.1k|      output[i - 1] = replacement;
  200|  28.1k|    }
  201|       |
  202|  8.26M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.21M, False: 52.5k]
  |  Branch (202:33): [True: 269k, False: 7.94M]
  ------------------
  203|   269k|      output[i] = replacement;
  204|  7.99M|    } else {
  205|  7.99M|      output[i] = input[i];
  206|  7.99M|    }
  207|  8.26M|    high_surrogate_prev = high_surrogate;
  208|  8.26M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.00k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 132, False: 873]
  ------------------
  212|    132|    output[i - 1] = replacement;
  213|    132|  }
  214|  1.00k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  8.26M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.26M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.26M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 640k, False: 7.62M]
  |  Branch (139:26): [True: 52.7k, False: 588k]
  ------------------
  140|  8.26M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  8.26M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.26M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.26M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 588k, False: 7.67M]
  |  Branch (144:26): [True: 294k, False: 293k]
  ------------------
  145|  8.26M|}

_ZN7simdutf6scalar5utf328validateEPKDim:
   25|    784|                                                        size_t len) noexcept {
   26|    784|  return validate(reinterpret_cast<const uint32_t *>(buf), len);
   27|    784|}
_ZN7simdutf6scalar5utf328validateIPKjQsr7simdutf6detailE19indexes_into_uint32IT_EEEbS5_m:
   13|    784|                                                      size_t len) noexcept {
   14|    784|  uint64_t pos = 0;
   15|  4.85k|  for (; pos < len; pos++) {
  ------------------
  |  Branch (15:10): [True: 4.71k, False: 138]
  ------------------
   16|  4.71k|    uint32_t word = data[pos];
   17|  4.71k|    if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) {
  ------------------
  |  Branch (17:9): [True: 553, False: 4.15k]
  |  Branch (17:29): [True: 783, False: 3.37k]
  |  Branch (17:47): [True: 93, False: 690]
  ------------------
   18|    646|      return false;
   19|    646|    }
   20|  4.71k|  }
   21|    138|  return true;
   22|    784|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_14utf88validateEPKcm:
  113|  1.26k|                                                        size_t len) noexcept {
  114|  1.26k|  return validate(reinterpret_cast<const uint8_t *>(buf), len);
  115|  1.26k|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_14utf88validateIPKhEEbT_m:
   14|  1.26k|                                                      size_t len) noexcept {
   15|  1.26k|  static_assert(
   16|  1.26k|      std::is_same<typename std::decay<decltype(*data)>::type, uint8_t>::value,
   17|  1.26k|      "dereferencing the data pointer must result in a uint8_t");
   18|  1.26k|  uint64_t pos = 0;
   19|  1.26k|  uint32_t code_point = 0;
   20|   376k|  while (pos < len) {
  ------------------
  |  Branch (20:10): [True: 376k, False: 109]
  ------------------
   21|   376k|    uint64_t next_pos;
   22|       |#if SIMDUTF_CPLUSPLUS23
   23|       |    if !consteval
   24|       |#endif
   25|   376k|    { // check if the next 16 bytes are ascii.
   26|   376k|      next_pos = pos + 16;
   27|   376k|      if (next_pos <= len) { // if it is safe to read 16 more bytes, check
  ------------------
  |  Branch (27:11): [True: 375k, False: 916]
  ------------------
   28|       |                             // that they are ascii
   29|   375k|        uint64_t v1{};
   30|   375k|        std::memcpy(&v1, data + pos, sizeof(uint64_t));
   31|   375k|        uint64_t v2{};
   32|   375k|        std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   33|   375k|        uint64_t v{v1 | v2};
   34|   375k|        if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (34:13): [True: 190k, False: 185k]
  ------------------
   35|   190k|          pos = next_pos;
   36|   190k|          continue;
   37|   190k|        }
   38|   375k|      }
   39|   376k|    }
   40|       |
   41|   185k|    unsigned char byte = data[pos];
   42|       |
   43|  1.81M|    while (byte < 0b10000000) {
  ------------------
  |  Branch (43:12): [True: 1.63M, False: 185k]
  ------------------
   44|  1.63M|      if (++pos == len) {
  ------------------
  |  Branch (44:11): [True: 75, False: 1.63M]
  ------------------
   45|     75|        return true;
   46|     75|      }
   47|  1.63M|      byte = data[pos];
   48|  1.63M|    }
   49|       |
   50|   185k|    if ((byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (50:9): [True: 13.9k, False: 171k]
  ------------------
   51|  13.9k|      next_pos = pos + 2;
   52|  13.9k|      if (next_pos > len) {
  ------------------
  |  Branch (52:11): [True: 25, False: 13.9k]
  ------------------
   53|     25|        return false;
   54|     25|      }
   55|  13.9k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (55:11): [True: 305, False: 13.6k]
  ------------------
   56|    305|        return false;
   57|    305|      }
   58|       |      // range check
   59|  13.6k|      code_point = (byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
   60|  13.6k|      if (code_point < 0x80) {
  ------------------
  |  Branch (60:11): [True: 7, False: 13.6k]
  ------------------
   61|      7|        return false;
   62|      7|      }
   63|   171k|    } else if ((byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (63:16): [True: 87.4k, False: 84.5k]
  ------------------
   64|  87.4k|      next_pos = pos + 3;
   65|  87.4k|      if (next_pos > len) {
  ------------------
  |  Branch (65:11): [True: 22, False: 87.4k]
  ------------------
   66|     22|        return false;
   67|     22|      }
   68|  87.4k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (68:11): [True: 94, False: 87.3k]
  ------------------
   69|     94|        return false;
   70|     94|      }
   71|  87.3k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (71:11): [True: 39, False: 87.3k]
  ------------------
   72|     39|        return false;
   73|     39|      }
   74|       |      // range check
   75|  87.3k|      code_point = (byte & 0b00001111) << 12 |
   76|  87.3k|                   (data[pos + 1] & 0b00111111) << 6 |
   77|  87.3k|                   (data[pos + 2] & 0b00111111);
   78|  87.3k|      if ((code_point < 0x800) ||
  ------------------
  |  Branch (78:11): [True: 4, False: 87.3k]
  ------------------
   79|  87.3k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (79:12): [True: 2.44k, False: 84.8k]
  |  Branch (79:35): [True: 3, False: 2.44k]
  ------------------
   80|      7|        return false;
   81|      7|      }
   82|  87.3k|    } else if ((byte & 0b11111000) == 0b11110000) { // 0b11110000
  ------------------
  |  Branch (82:16): [True: 84.0k, False: 485]
  ------------------
   83|  84.0k|      next_pos = pos + 4;
   84|  84.0k|      if (next_pos > len) {
  ------------------
  |  Branch (84:11): [True: 17, False: 84.0k]
  ------------------
   85|     17|        return false;
   86|     17|      }
   87|  84.0k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (87:11): [True: 45, False: 83.9k]
  ------------------
   88|     45|        return false;
   89|     45|      }
   90|  83.9k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (90:11): [True: 11, False: 83.9k]
  ------------------
   91|     11|        return false;
   92|     11|      }
   93|  83.9k|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (93:11): [True: 10, False: 83.9k]
  ------------------
   94|     10|        return false;
   95|     10|      }
   96|       |      // range check
   97|  83.9k|      code_point =
   98|  83.9k|          (byte & 0b00000111) << 18 | (data[pos + 1] & 0b00111111) << 12 |
   99|  83.9k|          (data[pos + 2] & 0b00111111) << 6 | (data[pos + 3] & 0b00111111);
  100|  83.9k|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (100:11): [True: 8, False: 83.9k]
  |  Branch (100:35): [True: 5, False: 83.9k]
  ------------------
  101|     13|        return false;
  102|     13|      }
  103|  83.9k|    } else {
  104|       |      // we may have a continuation
  105|    485|      return false;
  106|    485|    }
  107|   184k|    pos = next_pos;
  108|   184k|  }
  109|    109|  return true;
  110|  1.26k|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_14utf817trim_partial_utf8IPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEEmS6_m:
  292|     88|trim_partial_utf8(InputPtr input, size_t length) {
  293|     88|  if (length < 3) {
  ------------------
  |  Branch (293:7): [True: 35, False: 53]
  ------------------
  294|     35|    switch (length) {
  ------------------
  |  Branch (294:13): [True: 35, False: 0]
  ------------------
  295|     17|    case 2:
  ------------------
  |  Branch (295:5): [True: 17, False: 18]
  ------------------
  296|     17|      if (uint8_t(input[length - 1]) >= 0xc0) {
  ------------------
  |  Branch (296:11): [True: 2, False: 15]
  ------------------
  297|      2|        return length - 1;
  298|      2|      } // 2-, 3- and 4-byte characters with only 1 byte left
  299|     15|      if (uint8_t(input[length - 2]) >= 0xe0) {
  ------------------
  |  Branch (299:11): [True: 4, False: 11]
  ------------------
  300|      4|        return length - 2;
  301|      4|      } // 3- and 4-byte characters with only 2 bytes left
  302|     11|      return length;
  303|     17|    case 1:
  ------------------
  |  Branch (303:5): [True: 17, False: 18]
  ------------------
  304|     17|      if (uint8_t(input[length - 1]) >= 0xc0) {
  ------------------
  |  Branch (304:11): [True: 5, False: 12]
  ------------------
  305|      5|        return length - 1;
  306|      5|      } // 2-, 3- and 4-byte characters with only 1 byte left
  307|     12|      return length;
  308|      1|    case 0:
  ------------------
  |  Branch (308:5): [True: 1, False: 34]
  ------------------
  309|      1|      return length;
  310|     35|    }
  311|     35|  }
  312|     53|  if (uint8_t(input[length - 1]) >= 0xc0) {
  ------------------
  |  Branch (312:7): [True: 19, False: 34]
  ------------------
  313|     19|    return length - 1;
  314|     19|  } // 2-, 3- and 4-byte characters with only 1 byte left
  315|     34|  if (uint8_t(input[length - 2]) >= 0xe0) {
  ------------------
  |  Branch (315:7): [True: 2, False: 32]
  ------------------
  316|      2|    return length - 2;
  317|      2|  } // 3- and 4-byte characters with only 1 byte left
  318|     32|  if (uint8_t(input[length - 3]) >= 0xf0) {
  ------------------
  |  Branch (318:7): [True: 2, False: 30]
  ------------------
  319|      2|    return length - 3;
  320|      2|  } // 4-byte characters with only 3 bytes left
  321|     30|  return length;
  322|     32|}

_ZN7simdutf3BOM9check_bomEPKhm:
   24|  4.04k|encoding_type check_bom(const uint8_t *byte, size_t length) {
   25|  4.04k|  if (length >= 2 && byte[0] == 0xff and byte[1] == 0xfe) {
  ------------------
  |  Branch (25:7): [True: 3.99k, False: 45]
  |  Branch (25:22): [True: 528, False: 3.46k]
  |  Branch (25:42): [True: 231, False: 297]
  ------------------
   26|    231|    if (length >= 4 && byte[2] == 0x00 and byte[3] == 0x0) {
  ------------------
  |  Branch (26:9): [True: 219, False: 12]
  |  Branch (26:24): [True: 69, False: 150]
  |  Branch (26:44): [True: 6, False: 63]
  ------------------
   27|      6|      return encoding_type::UTF32_LE;
   28|    225|    } else {
   29|    225|      return encoding_type::UTF16_LE;
   30|    225|    }
   31|  3.81k|  } else if (length >= 2 && byte[0] == 0xfe and byte[1] == 0xff) {
  ------------------
  |  Branch (31:14): [True: 3.76k, False: 45]
  |  Branch (31:29): [True: 123, False: 3.64k]
  |  Branch (31:49): [True: 6, False: 117]
  ------------------
   32|      6|    return encoding_type::UTF16_BE;
   33|  3.80k|  } else if (length >= 4 && byte[0] == 0x00 and byte[1] == 0x00 and
  ------------------
  |  Branch (33:14): [True: 3.24k, False: 564]
  |  Branch (33:29): [True: 1.07k, False: 2.16k]
  |  Branch (33:49): [True: 642, False: 432]
  ------------------
   34|    642|             byte[2] == 0xfe and byte[3] == 0xff) {
  ------------------
  |  Branch (34:14): [True: 90, False: 552]
  |  Branch (34:34): [True: 6, False: 84]
  ------------------
   35|      6|    return encoding_type::UTF32_BE;
   36|  3.79k|  } else if (length >= 3 && byte[0] == 0xef and byte[1] == 0xbb and
  ------------------
  |  Branch (36:14): [True: 3.51k, False: 285]
  |  Branch (36:29): [True: 291, False: 3.22k]
  |  Branch (36:49): [True: 117, False: 174]
  ------------------
   37|    117|             byte[2] == 0xbf) {
  ------------------
  |  Branch (37:14): [True: 6, False: 111]
  ------------------
   38|      6|    return encoding_type::UTF8;
   39|      6|  }
   40|  3.79k|  return encoding_type::unspecified;
   41|  4.04k|}
_ZN7simdutf3BOM9check_bomEPKcm:
   43|  4.04k|encoding_type check_bom(const char *byte, size_t length) {
   44|  4.04k|  return check_bom(reinterpret_cast<const uint8_t *>(byte), length);
   45|  4.04k|}

_ZNK7simdutf8fallback14implementation16detect_encodingsEPKcm:
    9|    660|                                 size_t length) const noexcept {
   10|       |  // If there is a BOM, then we trust it.
   11|    660|  auto bom_encoding = simdutf::BOM::check_bom(input, length);
   12|    660|  if (bom_encoding != encoding_type::unspecified) {
  ------------------
  |  Branch (12:7): [True: 41, False: 619]
  ------------------
   13|     41|    return bom_encoding;
   14|     41|  }
   15|    619|  int out = 0;
   16|       |  // todo: reimplement as a one-pass algorithm.
   17|    619|  if (validate_utf8(input, length)) {
  ------------------
  |  Branch (17:7): [True: 89, False: 530]
  ------------------
   18|     89|    out |= encoding_type::UTF8;
   19|     89|  }
   20|    619|  if ((length % 2) == 0) {
  ------------------
  |  Branch (20:7): [True: 377, False: 242]
  ------------------
   21|    377|    if (validate_utf16le(reinterpret_cast<const char16_t *>(input),
  ------------------
  |  Branch (21:9): [True: 216, False: 161]
  ------------------
   22|    377|                         length / 2)) {
   23|    216|      out |= encoding_type::UTF16_LE;
   24|    216|    }
   25|    377|  }
   26|    619|  if ((length % 4) == 0) {
  ------------------
  |  Branch (26:7): [True: 291, False: 328]
  ------------------
   27|    291|    if (validate_utf32(reinterpret_cast<const char32_t *>(input), length / 4)) {
  ------------------
  |  Branch (27:9): [True: 69, False: 222]
  ------------------
   28|     69|      out |= encoding_type::UTF32_LE;
   29|     69|    }
   30|    291|  }
   31|    619|  return out;
   32|    660|}
_ZNK7simdutf8fallback14implementation13validate_utf8EPKcm:
   37|  1.26k|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
   38|  1.26k|  return scalar::utf8::validate(buf, len);
   39|  1.26k|}
_ZNK7simdutf8fallback14implementation14validate_asciiEPKcm:
   51|    201|implementation::validate_ascii(const char *buf, size_t len) const noexcept {
   52|    201|  return scalar::ascii::validate(buf, len);
   53|    201|}
_ZNK7simdutf8fallback14implementation26validate_ascii_with_errorsEPKcm:
   56|    283|    const char *buf, size_t len) const noexcept {
   57|    283|  return scalar::ascii::validate_with_errors(buf, len);
   58|    283|}
_ZNK7simdutf8fallback14implementation25validate_utf16le_as_asciiEPKDsm:
   64|    225|                                          size_t len) const noexcept {
   65|    225|  return scalar::utf16::validate_as_ascii<endianness::LITTLE>(buf, len);
   66|    225|}
_ZNK7simdutf8fallback14implementation25validate_utf16be_as_asciiEPKDsm:
   70|    225|                                          size_t len) const noexcept {
   71|    225|  return scalar::utf16::validate_as_ascii<endianness::BIG>(buf, len);
   72|    225|}
_ZNK7simdutf8fallback14implementation16validate_utf16leEPKDsm:
   77|  1.50k|                                 size_t len) const noexcept {
   78|  1.50k|  return scalar::utf16::validate<endianness::LITTLE>(buf, len);
   79|  1.50k|}
_ZNK7simdutf8fallback14implementation16validate_utf16beEPKDsm:
   85|    711|                                 size_t len) const noexcept {
   86|    711|  return scalar::utf16::validate<endianness::BIG>(buf, len);
   87|    711|}
_ZNK7simdutf8fallback14implementation22to_well_formed_utf16leEPKDsmPDs:
  100|    687|                                            char16_t *output) const noexcept {
  101|    687|  return scalar::utf16::to_well_formed_utf16<endianness::LITTLE>(input, len,
  102|    687|                                                                 output);
  103|    687|}
_ZNK7simdutf8fallback14implementation22to_well_formed_utf16beEPKDsmPDs:
  106|    687|                                            char16_t *output) const noexcept {
  107|    687|  return scalar::utf16::to_well_formed_utf16<endianness::BIG>(input, len,
  108|    687|                                                              output);
  109|    687|}
_ZNK7simdutf8fallback14implementation14validate_utf32EPKDim:
  114|    515|implementation::validate_utf32(const char32_t *buf, size_t len) const noexcept {
  115|    515|  return scalar::utf32::validate(buf, len);
  116|    515|}
_ZNK7simdutf8fallback14implementation23change_endianness_utf16EPKDsmPDs:
  414|    133|                                             char16_t *output) const noexcept {
  415|    133|  scalar::utf16::change_endianness_utf16(input, length, output);
  416|    133|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116ascii_validation22generic_validate_asciiEPKcm:
   32|    201|bool generic_validate_ascii(const char *input, size_t length) {
   33|    201|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
   34|  43.6k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (34:10): [True: 43.5k, False: 138]
  ------------------
   35|  43.5k|    simd::simd8x64<uint8_t> in(reader.full_block());
   36|  43.5k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (36:9): [True: 63, False: 43.4k]
  ------------------
   37|     63|      return false;
   38|     63|    }
   39|  43.4k|    reader.advance();
   40|  43.4k|  }
   41|    138|  uint8_t block[64]{};
   42|    138|  reader.get_remainder(block);
   43|    138|  simd::simd8x64<uint8_t> in(block);
   44|    138|  return in.is_ascii();
   45|    201|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116ascii_validation34generic_validate_ascii_with_errorsEPKcm:
    6|    283|result generic_validate_ascii_with_errors(const char *input, size_t length) {
    7|    283|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
    8|    283|  size_t count{0};
    9|  51.8k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (9:10): [True: 51.7k, False: 162]
  ------------------
   10|  51.7k|    simd::simd8x64<uint8_t> in(reader.full_block());
   11|  51.7k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (11:9): [True: 121, False: 51.5k]
  ------------------
   12|    121|      result res = scalar::ascii::validate_with_errors(
   13|    121|          reinterpret_cast<const char *>(input + count), length - count);
   14|    121|      return result(res.error, count + res.count);
   15|    121|    }
   16|  51.5k|    reader.advance();
   17|       |
   18|  51.5k|    count += 64;
   19|  51.5k|  }
   20|    162|  uint8_t block[64]{};
   21|    162|  reader.get_remainder(block);
   22|    162|  simd::simd8x64<uint8_t> in(block);
   23|    162|  if (!in.is_ascii()) {
  ------------------
  |  Branch (23:7): [True: 125, False: 37]
  ------------------
   24|    125|    result res = scalar::ascii::validate_with_errors(
   25|    125|        reinterpret_cast<const char *>(input + count), length - count);
   26|    125|    return result(res.error, count + res.count);
   27|    125|  } else {
   28|     37|    return result(error_code::SUCCESS, length);
   29|     37|  }
   30|    162|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116ascii_validation22generic_validate_asciiEPKcm:
   32|    201|bool generic_validate_ascii(const char *input, size_t length) {
   33|    201|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
   34|  43.6k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (34:10): [True: 43.5k, False: 138]
  ------------------
   35|  43.5k|    simd::simd8x64<uint8_t> in(reader.full_block());
   36|  43.5k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (36:9): [True: 63, False: 43.4k]
  ------------------
   37|     63|      return false;
   38|     63|    }
   39|  43.4k|    reader.advance();
   40|  43.4k|  }
   41|    138|  uint8_t block[64]{};
   42|    138|  reader.get_remainder(block);
   43|    138|  simd::simd8x64<uint8_t> in(block);
   44|    138|  return in.is_ascii();
   45|    201|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116ascii_validation34generic_validate_ascii_with_errorsEPKcm:
    6|    283|result generic_validate_ascii_with_errors(const char *input, size_t length) {
    7|    283|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
    8|    283|  size_t count{0};
    9|  51.8k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (9:10): [True: 51.7k, False: 162]
  ------------------
   10|  51.7k|    simd::simd8x64<uint8_t> in(reader.full_block());
   11|  51.7k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (11:9): [True: 121, False: 51.5k]
  ------------------
   12|    121|      result res = scalar::ascii::validate_with_errors(
   13|    121|          reinterpret_cast<const char *>(input + count), length - count);
   14|    121|      return result(res.error, count + res.count);
   15|    121|    }
   16|  51.5k|    reader.advance();
   17|       |
   18|  51.5k|    count += 64;
   19|  51.5k|  }
   20|    162|  uint8_t block[64]{};
   21|    162|  reader.get_remainder(block);
   22|    162|  simd::simd8x64<uint8_t> in(block);
   23|    162|  if (!in.is_ascii()) {
  ------------------
  |  Branch (23:7): [True: 125, False: 37]
  ------------------
   24|    125|    result res = scalar::ascii::validate_with_errors(
   25|    125|        reinterpret_cast<const char *>(input + count), length - count);
   26|    125|    return result(res.error, count + res.count);
   27|    125|  } else {
   28|     37|    return result(error_code::SUCCESS, length);
   29|     37|  }
   30|    162|}

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1623change_endianness_utf16EPKDsmPDs:
   56|    133|change_endianness_utf16(const char16_t *in, size_t size, char16_t *output) {
   57|    133|  size_t pos = 0;
   58|       |
   59|  82.2k|  while (pos < size / 32 * 32) {
  ------------------
  |  Branch (59:10): [True: 82.0k, False: 133]
  ------------------
   60|  82.0k|    simd16x32<uint16_t> input(reinterpret_cast<const uint16_t *>(in + pos));
   61|  82.0k|    input.swap_bytes();
   62|  82.0k|    input.store(reinterpret_cast<uint16_t *>(output));
   63|  82.0k|    pos += 32;
   64|  82.0k|    output += 32;
   65|  82.0k|  }
   66|       |
   67|    133|  scalar::utf16::change_endianness_utf16(in + pos, size - pos, output);
   68|    133|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1623change_endianness_utf16EPKDsmPDs:
   56|    133|change_endianness_utf16(const char16_t *in, size_t size, char16_t *output) {
   57|    133|  size_t pos = 0;
   58|       |
   59|  82.2k|  while (pos < size / 32 * 32) {
  ------------------
  |  Branch (59:10): [True: 82.0k, False: 133]
  ------------------
   60|  82.0k|    simd16x32<uint16_t> input(reinterpret_cast<const uint16_t *>(in + pos));
   61|  82.0k|    input.swap_bytes();
   62|  82.0k|    input.store(reinterpret_cast<uint16_t *>(output));
   63|  82.0k|    pos += 32;
   64|  82.0k|    output += 32;
   65|  82.0k|  }
   66|       |
   67|    133|  scalar::utf16::change_endianness_utf16(in + pos, size - pos, output);
   68|    133|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker16check_next_inputERKNS1_4simd8simd8x64IhEE:
  187|   625k|  simdutf_really_inline void check_next_input(const simd8x64<uint8_t> &input) {
  188|   625k|    if (simdutf_likely(is_ascii(input))) {
  ------------------
  |  |   90|   625k|    #define simdutf_likely(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (90:31): [True: 417k, False: 208k]
  |  |  ------------------
  ------------------
  189|   417k|      this->error |= this->prev_incomplete;
  190|   417k|    } else {
  191|       |      // you might think that a for-loop would work, but under Visual Studio, it
  192|       |      // is not good enough.
  193|   208k|      static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) ||
  194|   208k|                        (simd8x64<uint8_t>::NUM_CHUNKS == 4),
  195|   208k|                    "We support either two or four chunks per 64-byte block.");
  196|   208k|      if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
  197|   208k|        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  198|   208k|        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|   208k|      this->prev_incomplete =
  206|   208k|          is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1]);
  207|   208k|      this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1];
  208|   208k|    }
  209|   625k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker16check_utf8_bytesENS1_4simd5simd8IhEES6_:
  169|   417k|                                              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|   417k|    simd8<uint8_t> prev1 = input.prev<1>(prev_input);
  174|   417k|    simd8<uint8_t> sc = check_special_cases(input, prev1);
  175|   417k|    this->error |= check_multibyte_lengths(input, prev_input, sc);
  176|   417k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation19check_special_casesENS1_4simd5simd8IhEES5_:
    9|   417k|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|   417k|  constexpr const uint8_t TOO_SHORT = 1 << 0;  // 11______ 0_______
   17|       |                                               // 11______ 11______
   18|   417k|  constexpr const uint8_t TOO_LONG = 1 << 1;   // 0_______ 10______
   19|   417k|  constexpr const uint8_t OVERLONG_3 = 1 << 2; // 11100000 100_____
   20|   417k|  constexpr const uint8_t SURROGATE = 1 << 4;  // 11101101 101_____
   21|   417k|  constexpr const uint8_t OVERLONG_2 = 1 << 5; // 1100000_ 10______
   22|   417k|  constexpr const uint8_t TWO_CONTS = 1 << 7;  // 10______ 10______
   23|   417k|  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|   417k|  constexpr const uint8_t TOO_LARGE_1000 = 1 << 6;
   32|       |  // 11110101 1000____
   33|       |  // 1111011_ 1000____
   34|       |  // 11111___ 1000____
   35|   417k|  constexpr const uint8_t OVERLONG_4 = 1 << 6; // 11110000 1000____
   36|       |
   37|   417k|  const simd8<uint8_t> byte_1_high = prev1.shr<4>().lookup_16<uint8_t>(
   38|       |      // 0_______ ________ <ASCII in byte 1>
   39|   417k|      TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG,
   40|   417k|      TOO_LONG,
   41|       |      // 10______ ________ <continuation in byte 1>
   42|   417k|      TWO_CONTS, TWO_CONTS, TWO_CONTS, TWO_CONTS,
   43|       |      // 1100____ ________ <two byte lead in byte 1>
   44|   417k|      TOO_SHORT | OVERLONG_2,
   45|       |      // 1101____ ________ <two byte lead in byte 1>
   46|   417k|      TOO_SHORT,
   47|       |      // 1110____ ________ <three byte lead in byte 1>
   48|   417k|      TOO_SHORT | OVERLONG_3 | SURROGATE,
   49|       |      // 1111____ ________ <four+ byte lead in byte 1>
   50|   417k|      TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4);
   51|   417k|  constexpr const uint8_t CARRY =
   52|   417k|      TOO_SHORT | TOO_LONG | TWO_CONTS; // These all have ____ in byte 1 .
   53|   417k|  const simd8<uint8_t> byte_1_low =
   54|   417k|      (prev1 & 0x0F)
   55|   417k|          .lookup_16<uint8_t>(
   56|       |              // ____0000 ________
   57|   417k|              CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4,
   58|       |              // ____0001 ________
   59|   417k|              CARRY | OVERLONG_2,
   60|       |              // ____001_ ________
   61|   417k|              CARRY, CARRY,
   62|       |
   63|       |              // ____0100 ________
   64|   417k|              CARRY | TOO_LARGE,
   65|       |              // ____0101 ________
   66|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   67|       |              // ____011_ ________
   68|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   69|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   70|       |
   71|       |              // ____1___ ________
   72|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   73|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   74|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   75|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   76|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   77|       |              // ____1101 ________
   78|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE,
   79|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   80|   417k|              CARRY | TOO_LARGE | TOO_LARGE_1000);
   81|   417k|  const simd8<uint8_t> byte_2_high = input.shr<4>().lookup_16<uint8_t>(
   82|       |      // ________ 0_______ <ASCII in byte 2>
   83|   417k|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT,
   84|   417k|      TOO_SHORT, TOO_SHORT,
   85|       |
   86|       |      // ________ 1000____
   87|   417k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 |
   88|   417k|          OVERLONG_4,
   89|       |      // ________ 1001____
   90|   417k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE,
   91|       |      // ________ 101_____
   92|   417k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   93|   417k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   94|       |
   95|       |      // ________ 11______
   96|   417k|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT);
   97|   417k|  return (byte_1_high & byte_1_low & byte_2_high);
   98|   417k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation23check_multibyte_lengthsENS1_4simd5simd8IhEES5_S5_:
  102|   417k|                        const simd8<uint8_t> sc) {
  103|   417k|  simd8<uint8_t> prev2 = input.prev<2>(prev_input);
  104|   417k|  simd8<uint8_t> prev3 = input.prev<3>(prev_input);
  105|   417k|  simd8<uint8_t> must23 =
  106|   417k|      simd8<uint8_t>(must_be_2_3_continuation(prev2, prev3));
  107|   417k|  simd8<uint8_t> must23_80 = must23 & uint8_t(0x80);
  108|   417k|  return must23_80 ^ sc;
  109|   417k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation13is_incompleteENS1_4simd5simd8IhEE:
  115|   208k|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|   208k|  static const uint8_t max_array[32] = {255,
  120|   208k|                                        255,
  121|   208k|                                        255,
  122|   208k|                                        255,
  123|   208k|                                        255,
  124|   208k|                                        255,
  125|   208k|                                        255,
  126|   208k|                                        255,
  127|   208k|                                        255,
  128|   208k|                                        255,
  129|   208k|                                        255,
  130|   208k|                                        255,
  131|   208k|                                        255,
  132|   208k|                                        255,
  133|   208k|                                        255,
  134|   208k|                                        255,
  135|   208k|                                        255,
  136|   208k|                                        255,
  137|   208k|                                        255,
  138|   208k|                                        255,
  139|   208k|                                        255,
  140|   208k|                                        255,
  141|   208k|                                        255,
  142|   208k|                                        255,
  143|   208k|                                        255,
  144|   208k|                                        255,
  145|   208k|                                        255,
  146|   208k|                                        255,
  147|   208k|                                        255,
  148|   208k|                                        0b11110000u - 1,
  149|   208k|                                        0b11100000u - 1,
  150|   208k|                                        0b11000000u - 1};
  151|   208k|  const simd8<uint8_t> max_value(
  152|   208k|      &max_array[sizeof(max_array) - sizeof(simd8<uint8_t>)]);
  153|   208k|  return input.gt_bits(max_value);
  154|   208k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker9check_eofEv:
  181|  1.26k|  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|  1.26k|    this->error |= this->prev_incomplete;
  185|  1.26k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_115utf8_validation12utf8_checker6errorsEv:
  212|  1.26k|  simdutf_really_inline bool errors() const {
  213|  1.26k|    return this->error.any_bits_set_anywhere();
  214|  1.26k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker16check_next_inputERKNS1_4simd8simd8x64IhEE:
  187|   625k|  simdutf_really_inline void check_next_input(const simd8x64<uint8_t> &input) {
  188|   625k|    if (simdutf_likely(is_ascii(input))) {
  ------------------
  |  |   90|   625k|    #define simdutf_likely(x) __builtin_expect(!!(x), 1)
  |  |  ------------------
  |  |  |  Branch (90:31): [True: 417k, False: 208k]
  |  |  ------------------
  ------------------
  189|   417k|      this->error |= this->prev_incomplete;
  190|   417k|    } else {
  191|       |      // you might think that a for-loop would work, but under Visual Studio, it
  192|       |      // is not good enough.
  193|   208k|      static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) ||
  194|   208k|                        (simd8x64<uint8_t>::NUM_CHUNKS == 4),
  195|   208k|                    "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|   208k|      } else if constexpr (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
  200|   208k|        this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
  201|   208k|        this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
  202|   208k|        this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
  203|   208k|        this->check_utf8_bytes(input.chunks[3], input.chunks[2]);
  204|   208k|      }
  205|   208k|      this->prev_incomplete =
  206|   208k|          is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1]);
  207|   208k|      this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS - 1];
  208|   208k|    }
  209|   625k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker16check_utf8_bytesENS1_4simd5simd8IhEES6_:
  169|   834k|                                              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|   834k|    simd8<uint8_t> prev1 = input.prev<1>(prev_input);
  174|   834k|    simd8<uint8_t> sc = check_special_cases(input, prev1);
  175|   834k|    this->error |= check_multibyte_lengths(input, prev_input, sc);
  176|   834k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation19check_special_casesENS1_4simd5simd8IhEES5_:
    9|   834k|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|   834k|  constexpr const uint8_t TOO_SHORT = 1 << 0;  // 11______ 0_______
   17|       |                                               // 11______ 11______
   18|   834k|  constexpr const uint8_t TOO_LONG = 1 << 1;   // 0_______ 10______
   19|   834k|  constexpr const uint8_t OVERLONG_3 = 1 << 2; // 11100000 100_____
   20|   834k|  constexpr const uint8_t SURROGATE = 1 << 4;  // 11101101 101_____
   21|   834k|  constexpr const uint8_t OVERLONG_2 = 1 << 5; // 1100000_ 10______
   22|   834k|  constexpr const uint8_t TWO_CONTS = 1 << 7;  // 10______ 10______
   23|   834k|  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|   834k|  constexpr const uint8_t TOO_LARGE_1000 = 1 << 6;
   32|       |  // 11110101 1000____
   33|       |  // 1111011_ 1000____
   34|       |  // 11111___ 1000____
   35|   834k|  constexpr const uint8_t OVERLONG_4 = 1 << 6; // 11110000 1000____
   36|       |
   37|   834k|  const simd8<uint8_t> byte_1_high = prev1.shr<4>().lookup_16<uint8_t>(
   38|       |      // 0_______ ________ <ASCII in byte 1>
   39|   834k|      TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG, TOO_LONG,
   40|   834k|      TOO_LONG,
   41|       |      // 10______ ________ <continuation in byte 1>
   42|   834k|      TWO_CONTS, TWO_CONTS, TWO_CONTS, TWO_CONTS,
   43|       |      // 1100____ ________ <two byte lead in byte 1>
   44|   834k|      TOO_SHORT | OVERLONG_2,
   45|       |      // 1101____ ________ <two byte lead in byte 1>
   46|   834k|      TOO_SHORT,
   47|       |      // 1110____ ________ <three byte lead in byte 1>
   48|   834k|      TOO_SHORT | OVERLONG_3 | SURROGATE,
   49|       |      // 1111____ ________ <four+ byte lead in byte 1>
   50|   834k|      TOO_SHORT | TOO_LARGE | TOO_LARGE_1000 | OVERLONG_4);
   51|   834k|  constexpr const uint8_t CARRY =
   52|   834k|      TOO_SHORT | TOO_LONG | TWO_CONTS; // These all have ____ in byte 1 .
   53|   834k|  const simd8<uint8_t> byte_1_low =
   54|   834k|      (prev1 & 0x0F)
   55|   834k|          .lookup_16<uint8_t>(
   56|       |              // ____0000 ________
   57|   834k|              CARRY | OVERLONG_3 | OVERLONG_2 | OVERLONG_4,
   58|       |              // ____0001 ________
   59|   834k|              CARRY | OVERLONG_2,
   60|       |              // ____001_ ________
   61|   834k|              CARRY, CARRY,
   62|       |
   63|       |              // ____0100 ________
   64|   834k|              CARRY | TOO_LARGE,
   65|       |              // ____0101 ________
   66|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   67|       |              // ____011_ ________
   68|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   69|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   70|       |
   71|       |              // ____1___ ________
   72|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   73|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   74|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   75|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   76|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   77|       |              // ____1101 ________
   78|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000 | SURROGATE,
   79|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000,
   80|   834k|              CARRY | TOO_LARGE | TOO_LARGE_1000);
   81|   834k|  const simd8<uint8_t> byte_2_high = input.shr<4>().lookup_16<uint8_t>(
   82|       |      // ________ 0_______ <ASCII in byte 2>
   83|   834k|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT,
   84|   834k|      TOO_SHORT, TOO_SHORT,
   85|       |
   86|       |      // ________ 1000____
   87|   834k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE_1000 |
   88|   834k|          OVERLONG_4,
   89|       |      // ________ 1001____
   90|   834k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | OVERLONG_3 | TOO_LARGE,
   91|       |      // ________ 101_____
   92|   834k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   93|   834k|      TOO_LONG | OVERLONG_2 | TWO_CONTS | SURROGATE | TOO_LARGE,
   94|       |
   95|       |      // ________ 11______
   96|   834k|      TOO_SHORT, TOO_SHORT, TOO_SHORT, TOO_SHORT);
   97|   834k|  return (byte_1_high & byte_1_low & byte_2_high);
   98|   834k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation23check_multibyte_lengthsENS1_4simd5simd8IhEES5_S5_:
  102|   834k|                        const simd8<uint8_t> sc) {
  103|   834k|  simd8<uint8_t> prev2 = input.prev<2>(prev_input);
  104|   834k|  simd8<uint8_t> prev3 = input.prev<3>(prev_input);
  105|   834k|  simd8<uint8_t> must23 =
  106|   834k|      simd8<uint8_t>(must_be_2_3_continuation(prev2, prev3));
  107|   834k|  simd8<uint8_t> must23_80 = must23 & uint8_t(0x80);
  108|   834k|  return must23_80 ^ sc;
  109|   834k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation13is_incompleteENS1_4simd5simd8IhEE:
  115|   208k|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|   208k|  static const uint8_t max_array[32] = {255,
  120|   208k|                                        255,
  121|   208k|                                        255,
  122|   208k|                                        255,
  123|   208k|                                        255,
  124|   208k|                                        255,
  125|   208k|                                        255,
  126|   208k|                                        255,
  127|   208k|                                        255,
  128|   208k|                                        255,
  129|   208k|                                        255,
  130|   208k|                                        255,
  131|   208k|                                        255,
  132|   208k|                                        255,
  133|   208k|                                        255,
  134|   208k|                                        255,
  135|   208k|                                        255,
  136|   208k|                                        255,
  137|   208k|                                        255,
  138|   208k|                                        255,
  139|   208k|                                        255,
  140|   208k|                                        255,
  141|   208k|                                        255,
  142|   208k|                                        255,
  143|   208k|                                        255,
  144|   208k|                                        255,
  145|   208k|                                        255,
  146|   208k|                                        255,
  147|   208k|                                        255,
  148|   208k|                                        0b11110000u - 1,
  149|   208k|                                        0b11100000u - 1,
  150|   208k|                                        0b11000000u - 1};
  151|   208k|  const simd8<uint8_t> max_value(
  152|   208k|      &max_array[sizeof(max_array) - sizeof(simd8<uint8_t>)]);
  153|   208k|  return input.gt_bits(max_value);
  154|   208k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker9check_eofEv:
  181|  1.26k|  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|  1.26k|    this->error |= this->prev_incomplete;
  185|  1.26k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_115utf8_validation12utf8_checker6errorsEv:
  212|  1.26k|  simdutf_really_inline bool errors() const {
  213|  1.26k|    return this->error.any_bits_set_anywhere();
  214|  1.26k|  }

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    225|                                                 size_t size) {
  131|    225|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    225|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 223]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    223|  size_t pos = 0;
  135|    747|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 691, False: 56]
  ------------------
  136|    691|    simd16x32<uint16_t> input_vec(
  137|    691|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    691|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    691|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 167, False: 524]
  ------------------
  143|       |      // Found a match, return the first one
  144|    167|      int index = trailing_zeroes(~matches) / 2;
  145|    167|      return result(error_code::TOO_LARGE, pos + index);
  146|    167|    }
  147|    691|  }
  148|       |
  149|       |  // Scalar tail
  150|    160|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 135, False: 25]
  ------------------
  151|       |
  152|    135|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    135|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 31, False: 104]
  ------------------
  154|     31|      return result(error_code::TOO_LARGE, pos);
  155|     31|    }
  156|    104|    pos++;
  157|    104|  }
  158|     25|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    225|                                                 size_t size) {
  131|    225|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    225|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 223]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    223|  size_t pos = 0;
  135|    704|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 652, False: 52]
  ------------------
  136|    652|    simd16x32<uint16_t> input_vec(
  137|    652|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    652|    if constexpr (!match_system(big_endian)) {
  139|    652|      input_vec.swap_bytes();
  140|    652|    }
  141|    652|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    652|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 171, False: 481]
  ------------------
  143|       |      // Found a match, return the first one
  144|    171|      int index = trailing_zeroes(~matches) / 2;
  145|    171|      return result(error_code::TOO_LARGE, pos + index);
  146|    171|    }
  147|    652|  }
  148|       |
  149|       |  // Scalar tail
  150|    160|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 138, False: 22]
  ------------------
  151|       |
  152|    138|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    138|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 108]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    108|    pos++;
  157|    108|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.80k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.80k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.80k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.80k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.80k|  const char16_t *start = input;
   55|  1.80k|  const char16_t *end = input + size;
   56|       |
   57|  1.80k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.80k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.80k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.80k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   873k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 871k, False: 1.55k]
  ------------------
   63|       |    // 0. Load data: since the validation takes into account only higher
   64|       |    //    byte of each word, we compress the two vectors into one which
   65|       |    //    consists only the higher bytes.
   66|   871k|    auto in0 = simd16<uint16_t>(input);
   67|   871k|    auto in1 =
   68|   871k|        simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t));
   69|       |
   70|       |    // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16
   71|       |    // and yields a single vector having only higher bytes of characters.
   72|   871k|    const auto in = utf16_gather_high_bytes<big_endian>(in0, in1);
   73|       |
   74|       |    // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy).
   75|   871k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   871k|    const uint16_t surrogates_bitmask =
   77|   871k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   871k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 855k, False: 15.8k]
  ------------------
   79|   855k|      input += 16;
   80|   855k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  15.8k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  15.8k|      const auto vH = (in & v_fc) == v_dc;
   93|  15.8k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  15.8k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  15.8k|      const uint16_t a = static_cast<uint16_t>(
  100|  15.8k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  15.8k|      const uint16_t b = static_cast<uint16_t>(
  104|  15.8k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  15.8k|      const uint16_t c = static_cast<uint16_t>(
  107|  15.8k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  15.8k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 13.1k, False: 2.66k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  13.1k|        input += 16;
  113|  13.1k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.42k, False: 249]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  2.42k|        input += 15;
  119|  2.42k|      } else {
  120|    249|        return result(error_code::SURROGATE, input - start);
  121|    249|      }
  122|  15.8k|    }
  123|   871k|  }
  124|       |
  125|  1.55k|  return result(error_code::SUCCESS, input - start);
  126|  1.80k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|  1.39k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.39k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.39k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.39k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.39k|  const char16_t *start = input;
   55|  1.39k|  const char16_t *end = input + size;
   56|       |
   57|  1.39k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.39k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.39k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.39k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   597k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 596k, False: 1.19k]
  ------------------
   63|       |    // 0. Load data: since the validation takes into account only higher
   64|       |    //    byte of each word, we compress the two vectors into one which
   65|       |    //    consists only the higher bytes.
   66|   596k|    auto in0 = simd16<uint16_t>(input);
   67|   596k|    auto in1 =
   68|   596k|        simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t));
   69|       |
   70|       |    // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16
   71|       |    // and yields a single vector having only higher bytes of characters.
   72|   596k|    const auto in = utf16_gather_high_bytes<big_endian>(in0, in1);
   73|       |
   74|       |    // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy).
   75|   596k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   596k|    const uint16_t surrogates_bitmask =
   77|   596k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   596k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 580k, False: 15.5k]
  ------------------
   79|   580k|      input += 16;
   80|   580k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  15.5k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  15.5k|      const auto vH = (in & v_fc) == v_dc;
   93|  15.5k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  15.5k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  15.5k|      const uint16_t a = static_cast<uint16_t>(
  100|  15.5k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  15.5k|      const uint16_t b = static_cast<uint16_t>(
  104|  15.5k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  15.5k|      const uint16_t c = static_cast<uint16_t>(
  107|  15.5k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  15.5k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 12.8k, False: 2.69k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  12.8k|        input += 16;
  113|  12.8k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.49k, False: 199]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  2.49k|        input += 15;
  119|  2.49k|      } else {
  120|    199|        return result(error_code::SURROGATE, input - start);
  121|    199|      }
  122|  15.5k|    }
  123|   596k|  }
  124|       |
  125|  1.19k|  return result(error_code::SUCCESS, input - start);
  126|  1.39k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    225|                                                 size_t size) {
  131|    225|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    225|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 223]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    223|  size_t pos = 0;
  135|    747|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 691, False: 56]
  ------------------
  136|    691|    simd16x32<uint16_t> input_vec(
  137|    691|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    691|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    691|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 167, False: 524]
  ------------------
  143|       |      // Found a match, return the first one
  144|    167|      int index = trailing_zeroes(~matches) / 2;
  145|    167|      return result(error_code::TOO_LARGE, pos + index);
  146|    167|    }
  147|    691|  }
  148|       |
  149|       |  // Scalar tail
  150|    160|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 135, False: 25]
  ------------------
  151|       |
  152|    135|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    135|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 31, False: 104]
  ------------------
  154|     31|      return result(error_code::TOO_LARGE, pos);
  155|     31|    }
  156|    104|    pos++;
  157|    104|  }
  158|     25|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    225|                                                 size_t size) {
  131|    225|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    225|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 223]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    223|  size_t pos = 0;
  135|    704|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 652, False: 52]
  ------------------
  136|    652|    simd16x32<uint16_t> input_vec(
  137|    652|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    652|    if constexpr (!match_system(big_endian)) {
  139|    652|      input_vec.swap_bytes();
  140|    652|    }
  141|    652|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    652|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 171, False: 481]
  ------------------
  143|       |      // Found a match, return the first one
  144|    171|      int index = trailing_zeroes(~matches) / 2;
  145|    171|      return result(error_code::TOO_LARGE, pos + index);
  146|    171|    }
  147|    652|  }
  148|       |
  149|       |  // Scalar tail
  150|    160|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 138, False: 22]
  ------------------
  151|       |
  152|    138|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    138|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 108]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    108|    pos++;
  157|    108|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.12k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.12k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.12k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.12k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.12k|  const char16_t *start = input;
   55|  1.12k|  const char16_t *end = input + size;
   56|       |
   57|  1.12k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.12k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.12k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.12k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   761k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 759k, False: 1.01k]
  ------------------
   63|       |    // 0. Load data: since the validation takes into account only higher
   64|       |    //    byte of each word, we compress the two vectors into one which
   65|       |    //    consists only the higher bytes.
   66|   759k|    auto in0 = simd16<uint16_t>(input);
   67|   759k|    auto in1 =
   68|   759k|        simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t));
   69|       |
   70|       |    // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16
   71|       |    // and yields a single vector having only higher bytes of characters.
   72|   759k|    const auto in = utf16_gather_high_bytes<big_endian>(in0, in1);
   73|       |
   74|       |    // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy).
   75|   759k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   759k|    const uint16_t surrogates_bitmask =
   77|   759k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   759k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 746k, False: 13.9k]
  ------------------
   79|   746k|      input += 16;
   80|   746k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  13.9k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  13.9k|      const auto vH = (in & v_fc) == v_dc;
   93|  13.9k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  13.9k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  13.9k|      const uint16_t a = static_cast<uint16_t>(
  100|  13.9k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  13.9k|      const uint16_t b = static_cast<uint16_t>(
  104|  13.9k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  13.9k|      const uint16_t c = static_cast<uint16_t>(
  107|  13.9k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  13.9k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 11.6k, False: 2.27k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  11.6k|        input += 16;
  113|  11.6k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.16k, False: 106]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  2.16k|        input += 15;
  119|  2.16k|      } else {
  120|    106|        return result(error_code::SURROGATE, input - start);
  121|    106|      }
  122|  13.9k|    }
  123|   759k|  }
  124|       |
  125|  1.01k|  return result(error_code::SUCCESS, input - start);
  126|  1.12k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|    708|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|    708|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    708|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 708]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|    708|  const char16_t *start = input;
   55|    708|  const char16_t *end = input + size;
   56|       |
   57|    708|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|    708|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|    708|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|    708|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   517k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 516k, False: 708]
  ------------------
   63|       |    // 0. Load data: since the validation takes into account only higher
   64|       |    //    byte of each word, we compress the two vectors into one which
   65|       |    //    consists only the higher bytes.
   66|   516k|    auto in0 = simd16<uint16_t>(input);
   67|   516k|    auto in1 =
   68|   516k|        simd16<uint16_t>(input + simd16<uint16_t>::SIZE / sizeof(char16_t));
   69|       |
   70|       |    // Function `utf16_gather_high_bytes` consumes two vectors of UTF-16
   71|       |    // and yields a single vector having only higher bytes of characters.
   72|   516k|    const auto in = utf16_gather_high_bytes<big_endian>(in0, in1);
   73|       |
   74|       |    // 1. Check whether we have any 0xD800..DFFF word (0b1101'1xxx'yyyy'yyyy).
   75|   516k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   516k|    const uint16_t surrogates_bitmask =
   77|   516k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   516k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 502k, False: 13.5k]
  ------------------
   79|   502k|      input += 16;
   80|   502k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  13.5k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  13.5k|      const auto vH = (in & v_fc) == v_dc;
   93|  13.5k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  13.5k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  13.5k|      const uint16_t a = static_cast<uint16_t>(
  100|  13.5k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  13.5k|      const uint16_t b = static_cast<uint16_t>(
  104|  13.5k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  13.5k|      const uint16_t c = static_cast<uint16_t>(
  107|  13.5k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  13.5k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 11.3k, False: 2.22k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  11.3k|        input += 16;
  113|  11.3k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.22k, False: 0]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  2.22k|        input += 15;
  119|  2.22k|      } else {
  120|      0|        return result(error_code::SURROGATE, input - start);
  121|      0|      }
  122|  13.5k|    }
  123|   516k|  }
  124|       |
  125|    708|  return result(error_code::SUCCESS, input - start);
  126|    708|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf328validateEPKDim:
    6|    224|simdutf_really_inline bool validate(const char32_t *input, size_t size) {
    7|    224|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    224|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 224]
  |  |  ------------------
  ------------------
    8|       |    // empty input is valid UTF-32. protect the implementation from
    9|       |    // handling nullptr
   10|      0|    return true;
   11|      0|  }
   12|       |
   13|    224|  const char32_t *end = input + size;
   14|       |
   15|    224|  using vector_u32 = simd32<uint32_t>;
   16|       |
   17|    224|  const auto standardmax = vector_u32::splat(0x10ffff);
   18|    224|  const auto offset = vector_u32::splat(0xffff2000);
   19|    224|  const auto standardoffsetmax = vector_u32::splat(0xfffff7ff);
   20|    224|  auto currentmax = vector_u32::zero();
   21|    224|  auto currentoffsetmax = vector_u32::zero();
   22|       |
   23|    224|  constexpr size_t N = vector_u32::ELEMENTS;
   24|       |
   25|   353k|  while (input + N < end) {
  ------------------
  |  Branch (25:10): [True: 352k, False: 224]
  ------------------
   26|   352k|    auto in = vector_u32(input);
   27|   352k|    if constexpr (!match_system(endianness::BIG)) {
   28|   352k|      in.swap_bytes();
   29|   352k|    }
   30|       |
   31|   352k|    currentmax = max(currentmax, in);
   32|   352k|    currentoffsetmax = max(currentoffsetmax, in + offset);
   33|   352k|    input += N;
   34|   352k|  }
   35|       |
   36|    224|  const auto too_large = currentmax > standardmax;
   37|    224|  if (too_large.any()) {
  ------------------
  |  Branch (37:7): [True: 78, False: 146]
  ------------------
   38|     78|    return false;
   39|     78|  }
   40|       |
   41|    146|  const auto surrogate = currentoffsetmax > standardoffsetmax;
   42|    146|  if (surrogate.any()) {
  ------------------
  |  Branch (42:7): [True: 3, False: 143]
  ------------------
   43|      3|    return false;
   44|      3|  }
   45|       |
   46|    143|  return scalar::utf32::validate(input, end - input);
   47|    146|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf328validateEPKDim:
    6|    224|simdutf_really_inline bool validate(const char32_t *input, size_t size) {
    7|    224|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    224|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 224]
  |  |  ------------------
  ------------------
    8|       |    // empty input is valid UTF-32. protect the implementation from
    9|       |    // handling nullptr
   10|      0|    return true;
   11|      0|  }
   12|       |
   13|    224|  const char32_t *end = input + size;
   14|       |
   15|    224|  using vector_u32 = simd32<uint32_t>;
   16|       |
   17|    224|  const auto standardmax = vector_u32::splat(0x10ffff);
   18|    224|  const auto offset = vector_u32::splat(0xffff2000);
   19|    224|  const auto standardoffsetmax = vector_u32::splat(0xfffff7ff);
   20|    224|  auto currentmax = vector_u32::zero();
   21|    224|  auto currentoffsetmax = vector_u32::zero();
   22|       |
   23|    224|  constexpr size_t N = vector_u32::ELEMENTS;
   24|       |
   25|   706k|  while (input + N < end) {
  ------------------
  |  Branch (25:10): [True: 706k, False: 224]
  ------------------
   26|   706k|    auto in = vector_u32(input);
   27|   706k|    if constexpr (!match_system(endianness::BIG)) {
   28|   706k|      in.swap_bytes();
   29|   706k|    }
   30|       |
   31|   706k|    currentmax = max(currentmax, in);
   32|   706k|    currentoffsetmax = max(currentoffsetmax, in + offset);
   33|   706k|    input += N;
   34|   706k|  }
   35|       |
   36|    224|  const auto too_large = currentmax > standardmax;
   37|    224|  if (too_large.any()) {
  ------------------
  |  Branch (37:7): [True: 92, False: 132]
  ------------------
   38|     92|    return false;
   39|     92|  }
   40|       |
   41|    132|  const auto surrogate = currentoffsetmax > standardoffsetmax;
   42|    132|  if (surrogate.any()) {
  ------------------
  |  Branch (42:7): [True: 6, False: 126]
  ------------------
   43|      6|    return false;
   44|      6|  }
   45|       |
   46|    126|  return scalar::utf32::validate(input, end - input);
   47|    132|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_127avx2_convert_latin1_to_utf8EPKcmPc:
    3|    552|                            char *utf8_output) {
    4|    552|  const char *end = latin1_input + len;
    5|    552|  const __m256i v_0000 = _mm256_setzero_si256();
    6|    552|  const __m256i v_c080 = _mm256_set1_epi16((int16_t)0xc080);
    7|    552|  const __m256i v_ff80 = _mm256_set1_epi16((int16_t)0xff80);
    8|    552|  const size_t safety_margin = 12;
    9|       |
   10|  1.24M|  while (end - latin1_input >= std::ptrdiff_t(16 + safety_margin)) {
  ------------------
  |  Branch (10:10): [True: 1.24M, False: 552]
  ------------------
   11|  1.24M|    __m128i in8 = _mm_loadu_si128((__m128i *)latin1_input);
   12|       |    // a single 16-bit UTF-16 word can yield 1, 2 or 3 UTF-8 bytes
   13|  1.24M|    const __m128i v_80 = _mm_set1_epi8((char)0x80);
   14|  1.24M|    if (_mm_testz_si128(in8, v_80)) { // ASCII fast path!!!!
  ------------------
  |  Branch (14:9): [True: 401k, False: 842k]
  ------------------
   15|       |      // 1. store (16 bytes)
   16|   401k|      _mm_storeu_si128((__m128i *)utf8_output, in8);
   17|       |      // 2. adjust pointers
   18|   401k|      latin1_input += 16;
   19|   401k|      utf8_output += 16;
   20|   401k|      continue; // we are done for this round!
   21|   401k|    }
   22|       |    // We proceed only with the first 16 bytes.
   23|   842k|    const __m256i in = _mm256_cvtepu8_epi16((in8));
   24|       |
   25|       |    // 1. prepare 2-byte values
   26|       |    // input 16-bit word : [0000|0000|aabb|bbbb] x 8
   27|       |    // expected output   : [1100|00aa|10bb|bbbb] x 8
   28|   842k|    const __m256i v_1f00 = _mm256_set1_epi16((int16_t)0x1f00);
   29|   842k|    const __m256i v_003f = _mm256_set1_epi16((int16_t)0x003f);
   30|       |
   31|       |    // t0 = [0000|00aa|bbbb|bb00]
   32|   842k|    const __m256i t0 = _mm256_slli_epi16(in, 2);
   33|       |    // t1 = [0000|00aa|0000|0000]
   34|   842k|    const __m256i t1 = _mm256_and_si256(t0, v_1f00);
   35|       |    // t2 = [0000|0000|00bb|bbbb]
   36|   842k|    const __m256i t2 = _mm256_and_si256(in, v_003f);
   37|       |    // t3 = [000a|aaaa|00bb|bbbb]
   38|   842k|    const __m256i t3 = _mm256_or_si256(t1, t2);
   39|       |    // t4 = [1100|00aa|10bb|bbbb]
   40|   842k|    const __m256i t4 = _mm256_or_si256(t3, v_c080);
   41|       |
   42|       |    // 2. merge ASCII and 2-byte codewords
   43|       |
   44|       |    // no bits set above 7th bit
   45|   842k|    const __m256i one_byte_bytemask =
   46|   842k|        _mm256_cmpeq_epi16(_mm256_and_si256(in, v_ff80), v_0000);
   47|   842k|    const uint32_t one_byte_bitmask =
   48|   842k|        static_cast<uint32_t>(_mm256_movemask_epi8(one_byte_bytemask));
   49|       |
   50|   842k|    const __m256i utf8_unpacked = _mm256_blendv_epi8(t4, in, one_byte_bytemask);
   51|       |
   52|       |    // 3. prepare bitmask for 8-bit lookup
   53|   842k|    const uint32_t M0 = one_byte_bitmask & 0x55555555;
   54|   842k|    const uint32_t M1 = M0 >> 7;
   55|   842k|    const uint32_t M2 = (M1 | M0) & 0x00ff00ff;
   56|       |    // 4. pack the bytes
   57|       |
   58|   842k|    const uint8_t *row =
   59|   842k|        &simdutf::tables::utf16_to_utf8::pack_1_2_utf8_bytes[uint8_t(M2)][0];
   60|   842k|    const uint8_t *row_2 =
   61|   842k|        &simdutf::tables::utf16_to_utf8::pack_1_2_utf8_bytes[uint8_t(M2 >> 16)]
   62|   842k|                                                            [0];
   63|       |
   64|   842k|    const __m128i shuffle = _mm_loadu_si128((__m128i *)(row + 1));
   65|   842k|    const __m128i shuffle_2 = _mm_loadu_si128((__m128i *)(row_2 + 1));
   66|       |
   67|   842k|    const __m256i utf8_packed = _mm256_shuffle_epi8(
   68|   842k|        utf8_unpacked, _mm256_setr_m128i(shuffle, shuffle_2));
  ------------------
  |  |    7|   842k|      _mm256_permute2f128_si256(_mm256_castsi128_si256(xmm1),                  \
  |  |    8|   842k|                                _mm256_castsi128_si256(xmm2), 2)
  ------------------
   69|       |    // 5. store bytes
   70|   842k|    _mm_storeu_si128((__m128i *)utf8_output,
   71|   842k|                     _mm256_castsi256_si128(utf8_packed));
   72|   842k|    utf8_output += row[0];
   73|   842k|    _mm_storeu_si128((__m128i *)utf8_output,
   74|   842k|                     _mm256_extractf128_si256(utf8_packed, 1));
   75|   842k|    utf8_output += row_2[0];
   76|       |
   77|       |    // 6. adjust pointers
   78|   842k|    latin1_input += 16;
   79|   842k|    continue;
   80|       |
   81|  1.24M|  } // while
   82|    552|  return std::make_pair(latin1_input, utf8_output);
   83|    552|}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_avxILNS_10endiannessE0EEEvPKDsmPDs:
  143|    687|void utf16fix_avx(const char16_t *in, size_t n, char16_t *out) {
  144|    687|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  145|    687|  size_t i;
  146|       |
  147|    687|  if (n < 17) {
  ------------------
  |  Branch (147:7): [True: 299, False: 388]
  ------------------
  148|    299|    utf16fix_sse<big_endian>(in, n, out);
  149|    299|    return;
  150|    299|  }
  151|       |
  152|    388|  out[0] =
  153|    388|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (153:7): [True: 41, False: 347]
  ------------------
  154|       |
  155|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  156|    388|  if (in == out) {
  ------------------
  |  Branch (156:7): [True: 0, False: 388]
  ------------------
  157|      0|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (157:17): [True: 0, False: 0]
  ------------------
  158|      0|      utf16fix_block<big_endian, true>(out + i, in + i);
  159|      0|    }
  160|       |
  161|      0|    utf16fix_block<big_endian, true>(out + n - 16, in + n - 16);
  162|    388|  } else {
  163|   516k|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (163:17): [True: 516k, False: 388]
  ------------------
  164|   516k|      utf16fix_block<big_endian, false>(out + i, in + i);
  165|   516k|    }
  166|       |
  167|    388|    utf16fix_block<big_endian, false>(out + n - 16, in + n - 16);
  168|    388|  }
  169|       |
  170|    388|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (170:16): [True: 47, False: 341]
  ------------------
  171|    388|                   ? replacement
  172|    388|                   : out[n - 1];
  173|    388|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE0EEEvPKDsmPDs:
  110|    299|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
  111|    299|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  112|    299|  size_t i;
  113|       |
  114|    299|  if (n < 9) {
  ------------------
  |  Branch (114:7): [True: 159, False: 140]
  ------------------
  115|    159|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
  116|    159|    return;
  117|    159|  }
  118|       |
  119|    140|  out[0] =
  120|    140|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (120:7): [True: 22, False: 118]
  ------------------
  121|       |
  122|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  123|    140|  if (in == out) {
  ------------------
  |  Branch (123:7): [True: 0, False: 140]
  ------------------
  124|      0|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (124:17): [True: 0, False: 0]
  ------------------
  125|      0|      utf16fix_block_sse<big_endian, true>(out + i, in + i);
  126|      0|    }
  127|       |
  128|      0|    utf16fix_block_sse<big_endian, true>(out + n - 8, in + n - 8);
  129|    140|  } else {
  130|    160|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (130:17): [True: 20, False: 140]
  ------------------
  131|     20|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
  132|     20|    }
  133|       |
  134|    140|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
  135|    140|  }
  136|       |
  137|    140|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (137:16): [True: 20, False: 120]
  ------------------
  138|    140|                   ? replacement
  139|    140|                   : out[n - 1];
  140|    140|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDs:
   72|    160|void utf16fix_block_sse(char16_t *out, const char16_t *in) {
   73|    160|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    160|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    160|  };
   76|    160|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   77|    160|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   78|    160|  __m128i illseq, lb_illseq, block_illseq;
   79|       |
   80|    160|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   81|    160|  block = _mm_loadu_si128((const __m128i *)in);
   82|    160|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   83|    160|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   84|    160|  lb_is_high =
   85|    160|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   86|    160|  block_is_low =
   87|    160|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   88|       |
   89|    160|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   90|    160|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (90:7): [True: 91, False: 69]
  ------------------
   91|       |    /* compute the cause of the illegal sequencing */
   92|     91|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   93|     91|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   94|     91|                                _mm_bsrli_si128(lb_illseq, 2));
   95|       |    /* fix illegal sequencing in the lookback */
   96|     91|    int lb = _mm_cvtsi128_si32(lb_illseq);
   97|     91|    lb = (lb & replacement) | (~lb & out[-1]);
   98|     91|    out[-1] = char16_t(lb);
   99|       |    /* fix illegal sequencing in the main block */
  100|     91|    block =
  101|     91|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
  102|     91|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
  103|     91|    _mm_storeu_si128((__m128i *)out, block);
  104|     91|  } else if (!in_place) {
  ------------------
  |  Branch (104:14): [True: 69, Folded]
  ------------------
  105|     69|    _mm_storeu_si128((__m128i *)out, block);
  106|     69|  }
  107|    160|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDsENKUltE_clEt:
   73|    640|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    640|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    640|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE0ELb0EEEvPDsPKDs:
   10|   516k|void utf16fix_block(char16_t *out, const char16_t *in) {
   11|   516k|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|   516k|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|   516k|  };
   14|   516k|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   15|   516k|  __m256i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   16|   516k|  __m256i illseq, lb_illseq, block_illseq, lb_illseq_shifted;
   17|       |
   18|   516k|  lookback = _mm256_loadu_si256((const __m256i *)(in - 1));
   19|   516k|  block = _mm256_loadu_si256((const __m256i *)in);
   20|   516k|  lb_masked =
   21|   516k|      _mm256_and_si256(lookback, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   22|   516k|  block_masked =
   23|   516k|      _mm256_and_si256(block, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   24|   516k|  lb_is_high =
   25|   516k|      _mm256_cmpeq_epi16(lb_masked, _mm256_set1_epi16(swap_if_needed(0xd800u)));
   26|   516k|  block_is_low = _mm256_cmpeq_epi16(block_masked,
   27|   516k|                                    _mm256_set1_epi16(swap_if_needed(0xdc00u)));
   28|       |
   29|   516k|  illseq = _mm256_xor_si256(lb_is_high, block_is_low);
   30|   516k|  if (!_mm256_testz_si256(illseq, illseq)) {
  ------------------
  |  Branch (30:7): [True: 47.7k, False: 468k]
  ------------------
   31|  47.7k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  47.7k|    lb_illseq = _mm256_andnot_si256(block_is_low, lb_is_high);
   35|       |#if SIMDUTF_GCC9OROLDER
   36|       |    // Old GCC versions are missing _mm256_zextsi128_si256, so we emulate it.
   37|       |    __m128i tmp_legacygcc =
   38|       |        _mm_bslli_si128(_mm256_extracti128_si256(lb_illseq, 1), 14);
   39|       |    __m256i tmp_legacygcc256 =
   40|       |        _mm256_set_m128i(_mm_setzero_si128(), tmp_legacygcc);
   41|       |    lb_illseq_shifted =
   42|       |        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2), tmp_legacygcc256);
   43|       |#else
   44|  47.7k|    lb_illseq_shifted =
   45|  47.7k|        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2),
   46|  47.7k|                        _mm256_zextsi128_si256(_mm_bslli_si128(
   47|  47.7k|                            _mm256_extracti128_si256(lb_illseq, 1), 14)));
   48|  47.7k|#endif // SIMDUTF_GCC9OROLDER
   49|  47.7k|    block_illseq = _mm256_or_si256(
   50|  47.7k|        _mm256_andnot_si256(lb_is_high, block_is_low), lb_illseq_shifted);
   51|       |
   52|       |    /* fix illegal sequencing in the lookback */
   53|       |#if SIMDUTF_GCC10 || SIMDUTF_GCC9OROLDER
   54|       |    // GCC 10 is missing important intrinsics.
   55|       |    lb = _mm_cvtsi128_si32(_mm256_extractf128_si256(lb_illseq, 0));
   56|       |#else
   57|  47.7k|    lb = _mm256_cvtsi256_si32(lb_illseq);
   58|  47.7k|#endif
   59|  47.7k|    lb = (lb & replacement) | (~lb & out[-1]);
   60|  47.7k|    out[-1] = char16_t(lb);
   61|       |
   62|       |    /* fix illegal sequencing in the main block */
   63|  47.7k|    block =
   64|  47.7k|        _mm256_blendv_epi8(block, _mm256_set1_epi16(replacement), block_illseq);
   65|  47.7k|    _mm256_storeu_si256((__m256i *)out, block);
   66|   468k|  } else if (!in_place) {
  ------------------
  |  Branch (66:14): [True: 468k, Folded]
  ------------------
   67|   468k|    _mm256_storeu_si256((__m256i *)out, block);
   68|   468k|  }
   69|   516k|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE0ELb0EEEvPDsPKDsENKUltE_clEt:
   11|  2.06M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|  2.06M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|  2.06M|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_avxILNS_10endiannessE1EEEvPKDsmPDs:
  143|    687|void utf16fix_avx(const char16_t *in, size_t n, char16_t *out) {
  144|    687|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  145|    687|  size_t i;
  146|       |
  147|    687|  if (n < 17) {
  ------------------
  |  Branch (147:7): [True: 299, False: 388]
  ------------------
  148|    299|    utf16fix_sse<big_endian>(in, n, out);
  149|    299|    return;
  150|    299|  }
  151|       |
  152|    388|  out[0] =
  153|    388|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (153:7): [True: 45, False: 343]
  ------------------
  154|       |
  155|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  156|    388|  if (in == out) {
  ------------------
  |  Branch (156:7): [True: 0, False: 388]
  ------------------
  157|      0|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (157:17): [True: 0, False: 0]
  ------------------
  158|      0|      utf16fix_block<big_endian, true>(out + i, in + i);
  159|      0|    }
  160|       |
  161|      0|    utf16fix_block<big_endian, true>(out + n - 16, in + n - 16);
  162|    388|  } else {
  163|   516k|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (163:17): [True: 516k, False: 388]
  ------------------
  164|   516k|      utf16fix_block<big_endian, false>(out + i, in + i);
  165|   516k|    }
  166|       |
  167|    388|    utf16fix_block<big_endian, false>(out + n - 16, in + n - 16);
  168|    388|  }
  169|       |
  170|    388|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (170:16): [True: 30, False: 358]
  ------------------
  171|    388|                   ? replacement
  172|    388|                   : out[n - 1];
  173|    388|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE1EEEvPKDsmPDs:
  110|    299|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
  111|    299|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  112|    299|  size_t i;
  113|       |
  114|    299|  if (n < 9) {
  ------------------
  |  Branch (114:7): [True: 159, False: 140]
  ------------------
  115|    159|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
  116|    159|    return;
  117|    159|  }
  118|       |
  119|    140|  out[0] =
  120|    140|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (120:7): [True: 18, False: 122]
  ------------------
  121|       |
  122|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  123|    140|  if (in == out) {
  ------------------
  |  Branch (123:7): [True: 0, False: 140]
  ------------------
  124|      0|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (124:17): [True: 0, False: 0]
  ------------------
  125|      0|      utf16fix_block_sse<big_endian, true>(out + i, in + i);
  126|      0|    }
  127|       |
  128|      0|    utf16fix_block_sse<big_endian, true>(out + n - 8, in + n - 8);
  129|    140|  } else {
  130|    160|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (130:17): [True: 20, False: 140]
  ------------------
  131|     20|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
  132|     20|    }
  133|       |
  134|    140|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
  135|    140|  }
  136|       |
  137|    140|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (137:16): [True: 21, False: 119]
  ------------------
  138|    140|                   ? replacement
  139|    140|                   : out[n - 1];
  140|    140|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDs:
   72|    160|void utf16fix_block_sse(char16_t *out, const char16_t *in) {
   73|    160|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    160|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    160|  };
   76|    160|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   77|    160|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   78|    160|  __m128i illseq, lb_illseq, block_illseq;
   79|       |
   80|    160|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   81|    160|  block = _mm_loadu_si128((const __m128i *)in);
   82|    160|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   83|    160|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   84|    160|  lb_is_high =
   85|    160|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   86|    160|  block_is_low =
   87|    160|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   88|       |
   89|    160|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   90|    160|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (90:7): [True: 80, False: 80]
  ------------------
   91|       |    /* compute the cause of the illegal sequencing */
   92|     80|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   93|     80|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   94|     80|                                _mm_bsrli_si128(lb_illseq, 2));
   95|       |    /* fix illegal sequencing in the lookback */
   96|     80|    int lb = _mm_cvtsi128_si32(lb_illseq);
   97|     80|    lb = (lb & replacement) | (~lb & out[-1]);
   98|     80|    out[-1] = char16_t(lb);
   99|       |    /* fix illegal sequencing in the main block */
  100|     80|    block =
  101|     80|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
  102|     80|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
  103|     80|    _mm_storeu_si128((__m128i *)out, block);
  104|     80|  } else if (!in_place) {
  ------------------
  |  Branch (104:14): [True: 80, Folded]
  ------------------
  105|     80|    _mm_storeu_si128((__m128i *)out, block);
  106|     80|  }
  107|    160|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDsENKUltE_clEt:
   73|    640|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    640|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    640|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE1ELb0EEEvPDsPKDs:
   10|   516k|void utf16fix_block(char16_t *out, const char16_t *in) {
   11|   516k|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|   516k|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|   516k|  };
   14|   516k|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   15|   516k|  __m256i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   16|   516k|  __m256i illseq, lb_illseq, block_illseq, lb_illseq_shifted;
   17|       |
   18|   516k|  lookback = _mm256_loadu_si256((const __m256i *)(in - 1));
   19|   516k|  block = _mm256_loadu_si256((const __m256i *)in);
   20|   516k|  lb_masked =
   21|   516k|      _mm256_and_si256(lookback, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   22|   516k|  block_masked =
   23|   516k|      _mm256_and_si256(block, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   24|   516k|  lb_is_high =
   25|   516k|      _mm256_cmpeq_epi16(lb_masked, _mm256_set1_epi16(swap_if_needed(0xd800u)));
   26|   516k|  block_is_low = _mm256_cmpeq_epi16(block_masked,
   27|   516k|                                    _mm256_set1_epi16(swap_if_needed(0xdc00u)));
   28|       |
   29|   516k|  illseq = _mm256_xor_si256(lb_is_high, block_is_low);
   30|   516k|  if (!_mm256_testz_si256(illseq, illseq)) {
  ------------------
  |  Branch (30:7): [True: 47.5k, False: 468k]
  ------------------
   31|  47.5k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  47.5k|    lb_illseq = _mm256_andnot_si256(block_is_low, lb_is_high);
   35|       |#if SIMDUTF_GCC9OROLDER
   36|       |    // Old GCC versions are missing _mm256_zextsi128_si256, so we emulate it.
   37|       |    __m128i tmp_legacygcc =
   38|       |        _mm_bslli_si128(_mm256_extracti128_si256(lb_illseq, 1), 14);
   39|       |    __m256i tmp_legacygcc256 =
   40|       |        _mm256_set_m128i(_mm_setzero_si128(), tmp_legacygcc);
   41|       |    lb_illseq_shifted =
   42|       |        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2), tmp_legacygcc256);
   43|       |#else
   44|  47.5k|    lb_illseq_shifted =
   45|  47.5k|        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2),
   46|  47.5k|                        _mm256_zextsi128_si256(_mm_bslli_si128(
   47|  47.5k|                            _mm256_extracti128_si256(lb_illseq, 1), 14)));
   48|  47.5k|#endif // SIMDUTF_GCC9OROLDER
   49|  47.5k|    block_illseq = _mm256_or_si256(
   50|  47.5k|        _mm256_andnot_si256(lb_is_high, block_is_low), lb_illseq_shifted);
   51|       |
   52|       |    /* fix illegal sequencing in the lookback */
   53|       |#if SIMDUTF_GCC10 || SIMDUTF_GCC9OROLDER
   54|       |    // GCC 10 is missing important intrinsics.
   55|       |    lb = _mm_cvtsi128_si32(_mm256_extractf128_si256(lb_illseq, 0));
   56|       |#else
   57|  47.5k|    lb = _mm256_cvtsi256_si32(lb_illseq);
   58|  47.5k|#endif
   59|  47.5k|    lb = (lb & replacement) | (~lb & out[-1]);
   60|  47.5k|    out[-1] = char16_t(lb);
   61|       |
   62|       |    /* fix illegal sequencing in the main block */
   63|  47.5k|    block =
   64|  47.5k|        _mm256_blendv_epi8(block, _mm256_set1_epi16(replacement), block_illseq);
   65|  47.5k|    _mm256_storeu_si256((__m256i *)out, block);
   66|   468k|  } else if (!in_place) {
  ------------------
  |  Branch (66:14): [True: 468k, Folded]
  ------------------
   67|   468k|    _mm256_storeu_si256((__m256i *)out, block);
   68|   468k|  }
   69|   516k|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE1ELb0EEEvPDsPKDsENKUltE_clEt:
   11|  2.06M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|  2.06M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|  2.06M|  };

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1623utf16_gather_high_bytesILNS_10endiannessE0EEENS1_4simd5simd8IhEERKNS5_6simd16ItEESB_:
    3|   871k|                                       const simd16<uint16_t> &in1) {
    4|   871k|  if (big_endian) {
  ------------------
  |  Branch (4:7): [Folded, False: 871k]
  ------------------
    5|       |    // we want lower bytes
    6|      0|    const auto mask = simd16<uint16_t>(0x00ff);
    7|      0|    const auto t0 = in0 & mask;
    8|      0|    const auto t1 = in1 & mask;
    9|       |
   10|      0|    return simd16<uint16_t>::pack(t0, t1);
   11|   871k|  } else {
   12|   871k|    const auto t0 = in0.shr<8>();
   13|   871k|    const auto t1 = in1.shr<8>();
   14|       |
   15|   871k|    return simd16<uint16_t>::pack(t0, t1);
   16|   871k|  }
   17|   871k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1623utf16_gather_high_bytesILNS_10endiannessE1EEENS1_4simd5simd8IhEERKNS5_6simd16ItEESB_:
    3|   596k|                                       const simd16<uint16_t> &in1) {
    4|   596k|  if (big_endian) {
  ------------------
  |  Branch (4:7): [True: 596k, Folded]
  ------------------
    5|       |    // we want lower bytes
    6|   596k|    const auto mask = simd16<uint16_t>(0x00ff);
    7|   596k|    const auto t0 = in0 & mask;
    8|   596k|    const auto t1 = in1 & mask;
    9|       |
   10|   596k|    return simd16<uint16_t>::pack(t0, t1);
   11|   596k|  } else {
   12|      0|    const auto t0 = in0.shr<8>();
   13|      0|    const auto t1 = in1.shr<8>();
   14|       |
   15|      0|    return simd16<uint16_t>::pack(t0, t1);
   16|      0|  }
   17|   596k|}

_ZNK7simdutf7haswell14implementation16detect_encodingsEPKcm:
  156|    660|                                 size_t length) const noexcept {
  157|       |  // If there is a BOM, then we trust it.
  158|    660|  auto bom_encoding = simdutf::BOM::check_bom(input, length);
  159|    660|  if (bom_encoding != encoding_type::unspecified) {
  ------------------
  |  Branch (159:7): [True: 41, False: 619]
  ------------------
  160|     41|    return bom_encoding;
  161|     41|  }
  162|       |
  163|    619|  int out = 0;
  164|    619|  uint32_t utf16_err = (length % 2);
  165|    619|  uint32_t utf32_err = (length % 4);
  166|    619|  uint32_t ends_with_high = 0;
  167|    619|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
  168|    619|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
  169|    619|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
  170|    619|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
  171|    619|  const __m256i standardmax = _mm256_set1_epi32(0x10ffff);
  172|    619|  const __m256i offset = _mm256_set1_epi32(0xffff2000);
  173|    619|  const __m256i standardoffsetmax = _mm256_set1_epi32(0xfffff7ff);
  174|    619|  __m256i currentmax = _mm256_setzero_si256();
  175|    619|  __m256i currentoffsetmax = _mm256_setzero_si256();
  176|       |
  177|    619|  utf8_checker c{};
  178|    619|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
  179|   236k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (179:10): [True: 235k, False: 619]
  ------------------
  180|   235k|    simd::simd8x64<uint8_t> in(reader.full_block());
  181|       |    // utf8 checks
  182|   235k|    c.check_next_input(in);
  183|       |
  184|       |    // utf16le checks
  185|   235k|    auto in0 = simd16<uint16_t>(in.chunks[0]);
  186|   235k|    auto in1 = simd16<uint16_t>(in.chunks[1]);
  187|   235k|    const auto t0 = in0.shr<8>();
  188|   235k|    const auto t1 = in1.shr<8>();
  189|   235k|    const auto in2 = simd16<uint16_t>::pack(t0, t1);
  190|   235k|    const auto surrogates_wordmask = (in2 & v_f8) == v_d8;
  191|   235k|    const uint32_t surrogates_bitmask = surrogates_wordmask.to_bitmask();
  192|   235k|    const auto vL = (in2 & v_fc) == v_dc;
  193|   235k|    const uint32_t L = vL.to_bitmask();
  194|   235k|    const uint32_t H = L ^ surrogates_bitmask;
  195|   235k|    utf16_err |= (((H << 1) | ends_with_high) != L);
  196|   235k|    ends_with_high = (H & 0x80000000) != 0;
  197|       |
  198|       |    // utf32le checks
  199|   235k|    currentmax = _mm256_max_epu32(in.chunks[0], currentmax);
  200|   235k|    currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[0], offset),
  201|   235k|                                        currentoffsetmax);
  202|   235k|    currentmax = _mm256_max_epu32(in.chunks[1], currentmax);
  203|   235k|    currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[1], offset),
  204|   235k|                                        currentoffsetmax);
  205|       |
  206|   235k|    reader.advance();
  207|   235k|  }
  208|       |
  209|    619|  uint8_t block[64]{};
  210|    619|  size_t idx = reader.block_index();
  211|    619|  std::memcpy(block, &input[idx], length - idx);
  212|    619|  simd::simd8x64<uint8_t> in(block);
  213|    619|  c.check_next_input(in);
  214|       |
  215|       |  // utf16le last block check
  216|    619|  auto in0 = simd16<uint16_t>(in.chunks[0]);
  217|    619|  auto in1 = simd16<uint16_t>(in.chunks[1]);
  218|    619|  const auto t0 = in0.shr<8>();
  219|    619|  const auto t1 = in1.shr<8>();
  220|    619|  const auto in2 = simd16<uint16_t>::pack(t0, t1);
  221|    619|  const auto surrogates_wordmask = (in2 & v_f8) == v_d8;
  222|    619|  const uint32_t surrogates_bitmask = surrogates_wordmask.to_bitmask();
  223|    619|  const auto vL = (in2 & v_fc) == v_dc;
  224|    619|  const uint32_t L = vL.to_bitmask();
  225|    619|  const uint32_t H = L ^ surrogates_bitmask;
  226|    619|  utf16_err |= (((H << 1) | ends_with_high) != L);
  227|       |  // this is required to check for last byte ending in high and end of input
  228|       |  // is reached
  229|    619|  ends_with_high = (H & 0x80000000) != 0;
  230|    619|  utf16_err |= ends_with_high;
  231|       |
  232|       |  // utf32le last block check
  233|    619|  currentmax = _mm256_max_epu32(in.chunks[0], currentmax);
  234|    619|  currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[0], offset),
  235|    619|                                      currentoffsetmax);
  236|    619|  currentmax = _mm256_max_epu32(in.chunks[1], currentmax);
  237|    619|  currentoffsetmax = _mm256_max_epu32(_mm256_add_epi32(in.chunks[1], offset),
  238|    619|                                      currentoffsetmax);
  239|       |
  240|    619|  reader.advance();
  241|       |
  242|    619|  c.check_eof();
  243|    619|  bool is_valid_utf8 = !c.errors();
  244|    619|  __m256i is_zero =
  245|    619|      _mm256_xor_si256(_mm256_max_epu32(currentmax, standardmax), standardmax);
  246|    619|  utf32_err |= (_mm256_testz_si256(is_zero, is_zero) == 0);
  247|       |
  248|    619|  is_zero = _mm256_xor_si256(
  249|    619|      _mm256_max_epu32(currentoffsetmax, standardoffsetmax), standardoffsetmax);
  250|    619|  utf32_err |= (_mm256_testz_si256(is_zero, is_zero) == 0);
  251|    619|  if (is_valid_utf8) {
  ------------------
  |  Branch (251:7): [True: 89, False: 530]
  ------------------
  252|     89|    out |= encoding_type::UTF8;
  253|     89|  }
  254|    619|  if (utf16_err == 0) {
  ------------------
  |  Branch (254:7): [True: 216, False: 403]
  ------------------
  255|    216|    out |= encoding_type::UTF16_LE;
  256|    216|  }
  257|    619|  if (utf32_err == 0) {
  ------------------
  |  Branch (257:7): [True: 69, False: 550]
  ------------------
  258|     69|    out |= encoding_type::UTF32_LE;
  259|     69|  }
  260|    619|  return out;
  261|    660|}
_ZNK7simdutf7haswell14implementation13validate_utf8EPKcm:
  266|    645|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
  267|    645|  return haswell::utf8_validation::generic_validate_utf8(buf, len);
  268|    645|}
_ZNK7simdutf7haswell14implementation14validate_asciiEPKcm:
  280|    201|implementation::validate_ascii(const char *buf, size_t len) const noexcept {
  281|    201|  return haswell::ascii_validation::generic_validate_ascii(buf, len);
  282|    201|}
_ZNK7simdutf7haswell14implementation26validate_ascii_with_errorsEPKcm:
  285|    283|    const char *buf, size_t len) const noexcept {
  286|    283|  return haswell::ascii_validation::generic_validate_ascii_with_errors(buf,
  287|    283|                                                                       len);
  288|    283|}
_ZNK7simdutf7haswell14implementation25validate_utf16le_as_asciiEPKDsm:
  294|    225|                                          size_t len) const noexcept {
  295|    225|  return haswell::utf16::validate_utf16_as_ascii_with_errors<
  296|    225|             endianness::LITTLE>(buf, len)
  297|    225|             .error == SUCCESS;
  298|    225|}
_ZNK7simdutf7haswell14implementation25validate_utf16be_as_asciiEPKDsm:
  302|    225|                                          size_t len) const noexcept {
  303|    225|  return haswell::utf16::validate_utf16_as_ascii_with_errors<endianness::BIG>(
  304|    225|             buf, len)
  305|    225|             .error == SUCCESS;
  306|    225|}
_ZNK7simdutf7haswell14implementation16validate_utf16leEPKDsm:
  312|  1.81k|                                 size_t len) const noexcept {
  313|  1.81k|  if (simdutf_unlikely(len == 0)) {
  ------------------
  |  |   93|  1.81k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 4, False: 1.80k]
  |  |  ------------------
  ------------------
  314|       |    // empty input is valid UTF-16. protect the implementation from
  315|       |    // handling nullptr
  316|      4|    return true;
  317|      4|  }
  318|  1.80k|  const auto res =
  319|  1.80k|      haswell::utf16::validate_utf16_with_errors<endianness::LITTLE>(buf, len);
  320|  1.80k|  if (res.is_err()) {
  ------------------
  |  Branch (320:7): [True: 249, False: 1.55k]
  ------------------
  321|    249|    return false;
  322|    249|  }
  323|       |
  324|  1.55k|  if (res.count == len) {
  ------------------
  |  Branch (324:7): [True: 0, False: 1.55k]
  ------------------
  325|      0|    return true;
  326|      0|  }
  327|       |
  328|  1.55k|  return scalar::utf16::validate<endianness::LITTLE>(buf + res.count,
  329|  1.55k|                                                     len - res.count);
  330|  1.55k|}
_ZNK7simdutf7haswell14implementation16validate_utf16beEPKDsm:
  336|  1.39k|                                 size_t len) const noexcept {
  337|  1.39k|  if (simdutf_unlikely(len == 0)) {
  ------------------
  |  |   93|  1.39k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 4, False: 1.39k]
  |  |  ------------------
  ------------------
  338|       |    // empty input is valid UTF-16. protect the implementation from
  339|       |    // handling nullptr
  340|      4|    return true;
  341|      4|  }
  342|  1.39k|  const auto res =
  343|  1.39k|      haswell::utf16::validate_utf16_with_errors<endianness::BIG>(buf, len);
  344|  1.39k|  if (res.is_err()) {
  ------------------
  |  Branch (344:7): [True: 199, False: 1.19k]
  ------------------
  345|    199|    return false;
  346|    199|  }
  347|       |
  348|  1.19k|  if (res.count == len) {
  ------------------
  |  Branch (348:7): [True: 0, False: 1.19k]
  ------------------
  349|      0|    return true;
  350|      0|  }
  351|       |
  352|  1.19k|  return scalar::utf16::validate<endianness::BIG>(buf + res.count,
  353|  1.19k|                                                  len - res.count);
  354|  1.19k|}
_ZNK7simdutf7haswell14implementation22to_well_formed_utf16leEPKDsmPDs:
  386|    687|                                            char16_t *output) const noexcept {
  387|    687|  return utf16fix_avx<endianness::LITTLE>(input, len, output);
  388|    687|}
_ZNK7simdutf7haswell14implementation22to_well_formed_utf16beEPKDsmPDs:
  391|    687|                                            char16_t *output) const noexcept {
  392|    687|  return utf16fix_avx<endianness::BIG>(input, len, output);
  393|    687|}
_ZNK7simdutf7haswell14implementation14validate_utf32EPKDim:
  398|    224|implementation::validate_utf32(const char32_t *buf, size_t len) const noexcept {
  399|    224|  return utf32::validate(buf, len);
  400|    224|}
_ZNK7simdutf7haswell14implementation22convert_latin1_to_utf8EPKcmPc:
  412|    552|    const char *buf, size_t len, char *utf8_output) const noexcept {
  413|    552|  std::pair<const char *, char *> ret =
  414|    552|      avx2_convert_latin1_to_utf8(buf, len, utf8_output);
  415|    552|  size_t converted_chars = ret.second - utf8_output;
  416|       |
  417|    552|  if (ret.first != buf + len) {
  ------------------
  |  Branch (417:7): [True: 518, False: 34]
  ------------------
  418|    518|    const size_t scalar_converted_chars = scalar::latin1_to_utf8::convert(
  419|    518|        ret.first, len - (ret.first - buf), ret.second);
  420|    518|    converted_chars += scalar_converted_chars;
  421|    518|  }
  422|       |
  423|    552|  return converted_chars;
  424|    552|}
_ZNK7simdutf7haswell14implementation23change_endianness_utf16EPKDsmPDs:
 1100|    133|                                             char16_t *output) const noexcept {
 1101|    133|  utf16::change_endianness_utf16(input, length, output);
 1102|    133|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_18is_asciiERKNS1_4simd8simd8x64IhEE:
   13|   625k|simdutf_really_inline bool is_ascii(const simd8x64<uint8_t> &input) {
   14|   625k|  return input.reduce_or().is_ascii();
   15|   625k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_124must_be_2_3_continuationENS1_4simd5simd8IhEES4_:
   22|   417k|                         const simd8<uint8_t> prev3) {
   23|   417k|  simd8<uint8_t> is_third_byte =
   24|   417k|      prev2.saturating_sub(0xe0u - 0x80); // Only 111_____ will be > 0x80
   25|   417k|  simd8<uint8_t> is_fourth_byte =
   26|   417k|      prev3.saturating_sub(0xf0u - 0x80); // Only 1111____ will be > 0x80
   27|   417k|  return simd8<bool>(is_third_byte | is_fourth_byte);
   28|   417k|}

_ZNK7simdutf14implementation27supported_by_runtime_systemEv:
   64|      8|bool implementation::supported_by_runtime_system() const {
   65|      8|  uint32_t required_instruction_sets = this->required_instruction_sets();
   66|      8|  uint32_t supported_instruction_sets =
   67|      8|      internal::detect_supported_architectures();
   68|      8|  return ((supported_instruction_sets & required_instruction_sets) ==
   69|      8|          required_instruction_sets);
   70|      8|}
_ZNK7simdutf14implementation19autodetect_encodingEPKcm:
   74|  2.06k|    const char *input, size_t length) const noexcept {
   75|       |  // If there is a BOM, then we trust it.
   76|  2.06k|  auto bom_encoding = simdutf::BOM::check_bom(input, length);
   77|  2.06k|  if (bom_encoding != encoding_type::unspecified) {
  ------------------
  |  Branch (77:7): [True: 126, False: 1.93k]
  ------------------
   78|    126|    return bom_encoding;
   79|    126|  }
   80|       |  // UTF8 is common, it includes ASCII, and is commonly represented
   81|       |  // without a BOM, so if it fits, go with that. Note that it is still
   82|       |  // possible to get it wrong, we are only 'guessing'. If some has UTF-16
   83|       |  // data without a BOM, it could pass as UTF-8.
   84|       |  //
   85|       |  // An interesting twist might be to check for UTF-16 ASCII first (every
   86|       |  // other byte is zero).
   87|  1.93k|  if (validate_utf8(input, length)) {
  ------------------
  |  Branch (87:7): [True: 285, False: 1.65k]
  ------------------
   88|    285|    return encoding_type::UTF8;
   89|    285|  }
   90|       |  // The next most common encoding that might appear without BOM is probably
   91|       |  // UTF-16LE, so try that next.
   92|  1.65k|  if ((length % 2) == 0) {
  ------------------
  |  Branch (92:7): [True: 1.22k, False: 423]
  ------------------
   93|       |    // important: we need to divide by two
   94|  1.22k|    if (validate_utf16le(reinterpret_cast<const char16_t *>(input),
  ------------------
  |  Branch (94:9): [True: 342, False: 885]
  ------------------
   95|  1.22k|                         length / 2)) {
   96|    342|      return encoding_type::UTF16_LE;
   97|    342|    }
   98|  1.22k|  }
   99|  1.30k|  if ((length % 4) == 0) {
  ------------------
  |  Branch (99:7): [True: 672, False: 636]
  ------------------
  100|    672|    if (validate_utf32(reinterpret_cast<const char32_t *>(input), length / 4)) {
  ------------------
  |  Branch (100:9): [True: 69, False: 603]
  ------------------
  101|     69|      return encoding_type::UTF32_LE;
  102|     69|    }
  103|    672|  }
  104|  1.23k|  return encoding_type::unspecified;
  105|  1.30k|}
_ZNK7simdutf8internal29available_implementation_list5beginEv:
 1503|      1|available_implementation_list::begin() const noexcept {
 1504|      1|  return internal::get_available_implementation_pointers().begin();
 1505|      1|}
_ZNK7simdutf8internal29available_implementation_list3endEv:
 1507|      1|available_implementation_list::end() const noexcept {
 1508|      1|  return internal::get_available_implementation_pointers().end();
 1509|      1|}
_ZNK7simdutf8internal29available_implementation_list21detect_best_supportedEv:
 1511|      1|available_implementation_list::detect_best_supported() const noexcept {
 1512|       |  // They are prelisted in priority order, so we just go down the list
 1513|      1|  uint32_t supported_instruction_sets =
 1514|      1|      internal::detect_supported_architectures();
 1515|      1|  for (const implementation *impl :
  ------------------
  |  Branch (1515:35): [True: 2, False: 0]
  ------------------
 1516|      2|       internal::get_available_implementation_pointers()) {
 1517|      2|    uint32_t required_instruction_sets = impl->required_instruction_sets();
 1518|      2|    if ((supported_instruction_sets & required_instruction_sets) ==
  ------------------
  |  Branch (1518:9): [True: 1, False: 1]
  ------------------
 1519|      2|        required_instruction_sets) {
 1520|      1|      return impl;
 1521|      1|    }
 1522|      2|  }
 1523|      0|  return get_unsupported_singleton(); // this should never happen?
 1524|      1|}
_ZNK7simdutf8internal49detect_best_supported_implementation_on_first_use8set_bestEv:
 1527|      1|detect_best_supported_implementation_on_first_use::set_best() const noexcept {
 1528|      1|  SIMDUTF_PUSH_DISABLE_WARNINGS
 1529|       |  SIMDUTF_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC:
 1530|       |                                     // manually verified this is safe
 1531|      1|      char *force_implementation_name = getenv("SIMDUTF_FORCE_IMPLEMENTATION");
 1532|      1|  SIMDUTF_POP_DISABLE_WARNINGS
 1533|       |
 1534|      1|  if (force_implementation_name) {
  ------------------
  |  Branch (1534:7): [True: 0, False: 1]
  ------------------
 1535|      0|    auto force_implementation =
 1536|      0|        get_available_implementations()[force_implementation_name];
 1537|      0|    if (force_implementation) {
  ------------------
  |  Branch (1537:9): [True: 0, False: 0]
  ------------------
 1538|      0|      return get_active_implementation() = force_implementation;
 1539|      0|    } else {
 1540|       |      // Note: abort() and stderr usage within the library is forbidden.
 1541|      0|      return get_active_implementation() = get_unsupported_singleton();
 1542|      0|    }
 1543|      0|  }
 1544|      1|  return get_active_implementation() =
 1545|      1|             get_available_implementations().detect_best_supported();
 1546|      1|}
_ZN7simdutf29get_available_implementationsEv:
 1558|      2|get_available_implementations() {
 1559|      2|#if !SIMDUTF_USE_STATIC_INITIALIZATION
 1560|      2|  static const internal::available_implementation_list
 1561|      2|      available_implementations_instance{};
 1562|      2|#endif
 1563|      2|  return available_implementations_instance;
 1564|      2|}
_ZN7simdutf25get_active_implementationEv:
 1586|    553|get_active_implementation() {
 1587|    553|#if !SIMDUTF_USE_STATIC_INITIALIZATION
 1588|    553|  #if !SIMDUTF_SINGLE_IMPLEMENTATION
 1589|    553|  static const internal::detect_best_supported_implementation_on_first_use
 1590|    553|      detect_best_supported_implementation_on_first_use_singleton;
 1591|    553|  #endif
 1592|    553|  static internal::atomic_ptr<const implementation>
 1593|    553|      active_implementation_instance{
 1594|       |  #if SIMDUTF_SINGLE_IMPLEMENTATION
 1595|       |          internal::get_single_implementation()
 1596|       |  #else
 1597|    553|          &detect_best_supported_implementation_on_first_use_singleton
 1598|    553|  #endif
 1599|    553|      };
 1600|    553|#endif
 1601|    553|  return active_implementation_instance;
 1602|    553|}
_ZN7simdutf22convert_latin1_to_utf8EPKcmPc:
 1668|    552|                                                  char *utf8_output) noexcept {
 1669|    552|  return get_default_implementation()->convert_latin1_to_utf8(buf, len,
 1670|    552|                                                              utf8_output);
 1671|    552|}
_ZN7simdutf27convert_latin1_to_utf8_safeEPKcmPcm:
 2568|    277|    const char *buf, size_t len, char *utf8_output, size_t utf8_len) noexcept {
 2569|    277|  const auto start{utf8_output};
 2570|       |
 2571|    552|  while (true) {
  ------------------
  |  Branch (2571:10): [True: 552, Folded]
  ------------------
 2572|       |    // convert_latin1_to_utf8 will never write more than input length * 2
 2573|    552|    auto read_len = detail::min(len, utf8_len >> 1);
 2574|    552|    if (read_len <= 16) {
  ------------------
  |  Branch (2574:9): [True: 277, False: 275]
  ------------------
 2575|    277|      break;
 2576|    277|    }
 2577|       |
 2578|    275|    const auto write_len =
 2579|    275|        simdutf::convert_latin1_to_utf8(buf, read_len, utf8_output);
 2580|       |
 2581|    275|    utf8_output += write_len;
 2582|    275|    utf8_len -= write_len;
 2583|    275|    buf += read_len;
 2584|    275|    len -= read_len;
 2585|    275|  }
 2586|       |
 2587|    277|  utf8_output +=
 2588|    277|      scalar::latin1_to_utf8::convert_safe(buf, len, utf8_output, utf8_len);
 2589|       |
 2590|    277|  return utf8_output - start;
 2591|    277|}
_ZN7simdutf17trim_partial_utf8EPKcm:
 2655|     88|simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length) {
 2656|     88|  return scalar::utf8::trim_partial_utf8(input, length);
 2657|     88|}
_ZN7simdutf20trim_partial_utf16beEPKDsm:
 2662|     21|                                                size_t length) {
 2663|     21|  return scalar::utf16::trim_partial_utf16<BIG>(input, length);
 2664|     21|}
_ZN7simdutf20trim_partial_utf16leEPKDsm:
 2667|     33|                                                size_t length) {
 2668|     33|  return scalar::utf16::trim_partial_utf16<LITTLE>(input, length);
 2669|     33|}
simdutf.cpp:_ZN7simdutf8internalL37get_available_implementation_pointersEv:
  933|      3|get_available_implementation_pointers() {
  934|      3|#if !SIMDUTF_USE_STATIC_INITIALIZATION
  935|      3|  static const std::initializer_list<const implementation *>
  936|      3|      available_implementation_pointers{
  937|      3|  #if SIMDUTF_IMPLEMENTATION_ICELAKE
  938|      3|          get_icelake_singleton(),
  939|      3|  #endif
  940|      3|  #if SIMDUTF_IMPLEMENTATION_HASWELL
  941|      3|          get_haswell_singleton(),
  942|      3|  #endif
  943|      3|  #if SIMDUTF_IMPLEMENTATION_WESTMERE
  944|      3|          get_westmere_singleton(),
  945|      3|  #endif
  946|       |  #if SIMDUTF_IMPLEMENTATION_ARM64
  947|       |          get_arm64_singleton(),
  948|       |  #endif
  949|       |  #if SIMDUTF_IMPLEMENTATION_PPC64
  950|       |          get_ppc64_singleton(),
  951|       |  #endif
  952|       |  #if SIMDUTF_IMPLEMENTATION_RVV
  953|       |          get_rvv_singleton(),
  954|       |  #endif
  955|       |  #if SIMDUTF_IMPLEMENTATION_LASX
  956|       |          get_lasx_singleton(),
  957|       |  #endif
  958|       |  #if SIMDUTF_IMPLEMENTATION_LSX
  959|       |          get_lsx_singleton(),
  960|       |  #endif
  961|      3|  #if SIMDUTF_IMPLEMENTATION_FALLBACK
  962|      3|          get_fallback_singleton(),
  963|      3|  #endif
  964|      3|      };
  965|      3|#endif
  966|      3|  return available_implementation_pointers;
  967|      3|}
simdutf.cpp:_ZN7simdutf8internalL21get_icelake_singletonEv:
  157|      1|static const icelake::implementation *get_icelake_singleton() {
  158|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  159|      1|  static const icelake::implementation icelake_singleton{};
  160|      1|  #endif
  161|      1|  return &icelake_singleton;
  162|      1|}
simdutf.cpp:_ZN7simdutf8internalL21get_haswell_singletonEv:
  168|      1|static const haswell::implementation *get_haswell_singleton() {
  169|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  170|      1|  static const haswell::implementation haswell_singleton{};
  171|      1|  #endif
  172|      1|  return &haswell_singleton;
  173|      1|}
simdutf.cpp:_ZN7simdutf8internalL22get_westmere_singletonEv:
  179|      1|static const westmere::implementation *get_westmere_singleton() {
  180|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  181|      1|  static const westmere::implementation westmere_singleton{};
  182|      1|  #endif
  183|      1|  return &westmere_singleton;
  184|      1|}
simdutf.cpp:_ZN7simdutf8internalL22get_fallback_singletonEv:
  245|      1|static const fallback::implementation *get_fallback_singleton() {
  246|      1|  #if !SIMDUTF_USE_STATIC_INITIALIZATION
  247|      1|  static const fallback::implementation fallback_singleton{};
  248|      1|  #endif
  249|      1|  return &fallback_singleton;
  250|      1|}
_ZN7simdutf8internal49detect_best_supported_implementation_on_first_useC2Ev:
  887|      1|      : implementation("best_supported_detector",
  888|      1|                       "Detects the best supported implementation and sets it",
  889|      1|                       0) {}
_ZNK7simdutf8internal49detect_best_supported_implementation_on_first_use22convert_latin1_to_utf8EPKcmPc:
  394|      1|                         char *utf8_output) const noexcept final override {
  395|      1|    return set_best()->convert_latin1_to_utf8(buf, len, utf8_output);
  396|      1|  }
_ZN7simdutf26get_default_implementationEv:
 1610|    552|get_default_implementation() {
 1611|    552|  return get_active_implementation();
 1612|    552|}

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115trailing_zeroesEm:
   20|    338|simdutf_really_inline int trailing_zeroes(uint64_t input_num) {
   21|       |  #if SIMDUTF_REGULAR_VISUAL_STUDIO
   22|       |  return (int)_tzcnt_u64(input_num);
   23|       |  #else  // SIMDUTF_REGULAR_VISUAL_STUDIO
   24|    338|  return __builtin_ctzll(input_num);
   25|    338|  #endif // SIMDUTF_REGULAR_VISUAL_STUDIO
   26|    338|}

_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|  3.79k|  simdutf_really_inline simd8() : base8_numeric<uint8_t>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhEC2Ev:
  124|  3.79k|  simdutf_really_inline base8_numeric() : base8<T>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2Ev:
   71|  3.79k|  simdutf_really_inline base8() : base<simd8<T>>() {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2Ev:
   14|  3.79k|  simdutf_really_inline base() : value{__m256i()} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd8simd8x64IhE9reduce_orEv:
  294|   721k|  simdutf_really_inline simd8<T> reduce_or() const {
  295|   721k|    return this->chunks[0] | this->chunks[1];
  296|   721k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEorES5_:
   50|  1.97M|  simdutf_really_inline Child operator|(const Child other) const {
   51|  1.97M|    return _mm256_or_si256(*this, other);
   52|  1.97M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2EDv4_x:
  193|  18.7M|      : base8_numeric<uint8_t>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhEC2EDv4_x:
  126|  18.7M|      : base8<T>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2EDv4_x:
   73|  18.7M|  simdutf_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2EDv4_x:
   17|  18.7M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE8is_asciiEv:
  234|   721k|  simdutf_really_inline bool is_ascii() const {
  235|   721k|    return _mm256_movemask_epi8(*this) == 0;
  236|   721k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEoRES5_:
   59|   835k|  simdutf_really_inline Child &operator|=(const Child other) {
   60|   835k|    auto this_cast = static_cast<Child *>(this);
   61|   835k|    *this_cast = *this_cast | other;
   62|   835k|    return *this_cast;
   63|   835k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi1EEENS4_IhEES8_:
   83|   417k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|   417k|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|   417k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE3shrILi4EEES4_v:
  245|   834k|  template <int N> simdutf_really_inline simd8<uint8_t> shr() const {
  246|   834k|    return simd8<uint8_t>(_mm256_srli_epi16(*this, N)) & uint8_t(0xFFu >> N);
  247|   834k|  }
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|  1.25M|            L replace15) const {
  158|  1.25M|    return lookup_16(simd8<L>::repeat_16(
  159|  1.25M|        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
  160|  1.25M|        replace7, replace8, replace9, replace10, replace11, replace12,
  161|  1.25M|        replace13, replace14, replace15));
  162|  1.25M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES8_:
  148|  1.25M|  simdutf_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
  149|  1.25M|    return _mm256_shuffle_epi8(lookup_table, *this);
  150|  1.25M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE9repeat_16Ehhhhhhhhhhhhhhhh:
  118|  1.25M|                                                  T v14, T v15) {
  119|  1.25M|    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
  120|  1.25M|                    v14, v15, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  121|  1.25M|                    v12, v13, v14, v15);
  122|  1.25M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2Ehhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh:
  207|  1.25M|      : simd8(_mm256_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  208|  1.25M|                               v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
  209|  1.25M|                               v22, v23, v24, v25, v26, v27, v28, v29, v30,
  210|  1.25M|                               v31)) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2Eh:
  195|  2.50M|  simdutf_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi2EEENS4_IhEES8_:
   83|   417k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|   417k|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|   417k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi3EEENS4_IhEES8_:
   83|   417k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   84|       |    return _mm256_alignr_epi8(
   85|   417k|        *this, _mm256_permute2x128_si256(prev_chunk, *this, 0x21), 16 - N);
   86|   417k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE14saturating_subES4_:
  214|  1.04M|  saturating_sub(const simd8<uint8_t> other) const {
  215|  1.04M|    return _mm256_subs_epu8(*this, other);
  216|  1.04M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IbEC2EDv4_x:
   95|  2.38M|  simdutf_really_inline simd8(const __m256i _value) : base8<bool>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5base8IbNS2_5simd8IbEEEC2EDv4_x:
   73|  2.38M|  simdutf_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEC2EDv4_x:
   17|  2.38M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEcvRKDv4_xEv:
   19|   417k|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEeoES5_:
   56|   417k|  simdutf_really_inline Child operator^(const Child other) const {
   57|   417k|    return _mm256_xor_si256(*this, other);
   58|   417k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd5simd8IhEC2EPKh:
  197|   208k|  simdutf_really_inline simd8(const uint8_t values[32]) : simd8(load(values)) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE4loadEPKh:
  111|  1.65M|  static simdutf_really_inline simd8<T> load(const T values[32]) {
  112|  1.65M|    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(values));
  113|  1.65M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE7gt_bitsES4_:
  225|   208k|  gt_bits(const simd8<uint8_t> other) const {
  226|   208k|    return this->saturating_sub(other);
  227|   208k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEC2EDv4_x:
   17|  7.75M|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEcvRKDv4_xEv:
   19|  11.7M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IbE10to_bitmaskEv:
   99|  1.97M|  simdutf_really_inline uint32_t to_bitmask() const {
  100|  1.97M|    return uint32_t(_mm256_movemask_epi8(value));
  101|  1.97M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE21any_bits_set_anywhereEv:
  241|  1.26k|  simdutf_really_inline bool any_bits_set_anywhere() const {
  242|  1.26k|    return !bits_not_set_anywhere();
  243|  1.26k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd5simd8IhE21bits_not_set_anywhereEv:
  237|  1.26k|  simdutf_really_inline bool bits_not_set_anywhere() const {
  238|  1.26k|    return _mm256_testz_si256(*this, *this);
  239|  1.26k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd8simd8x64IhE8is_asciiEv:
  298|  95.5k|  simdutf_really_inline bool is_ascii() const {
  299|  95.5k|    return this->reduce_or().is_ascii();
  300|  95.5k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEC2EDv4_x:
   17|  2.68k|  simdutf_really_inline base(const __m256i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEcvRKDv4_xEv:
   19|  2.68k|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd13base8_numericIhE5splatEh:
  105|  2.51M|  static simdutf_really_inline simd8<T> splat(T _value) {
  106|  2.51M|    return _mm256_set1_epi8(_value);
  107|  2.51M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEcvRKDv4_xEv:
   19|  29.4M|  simdutf_really_inline operator const __m256i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdeqENS2_5simd8IhEES4_:
   76|  1.97M|                                               const simd8<T> rhs) {
   77|  1.97M|    return _mm256_cmpeq_epi8(lhs, rhs);
   78|  1.97M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEanES5_:
   53|  4.47M|  simdutf_really_inline Child operator&(const Child other) const {
   54|  4.47M|    return _mm256_and_si256(*this, other);
   55|  4.47M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd8simd8x64IhEC2EPKh:
  274|   721k|      : chunks{simd8<T>::load(ptr),
  275|   721k|               simd8<T>::load(ptr + sizeof(simd8<T>) / sizeof(T))} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEanES5_:
   53|  1.19M|  simdutf_really_inline Child operator&(const Child other) const {
   54|  1.19M|    return _mm256_and_si256(*this, other);
   55|  1.19M|  }

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEC2EDv4_x:
   97|  7.75M|      : base16_numeric<uint16_t>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItEC2EDv4_x:
   73|  7.75M|      : base16<T>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6base16ItNS2_6simd16IbEEEC2EDv4_x:
   20|  7.75M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE4packERKS4_S6_:
  149|  1.70M|                                                   const simd16<uint16_t> &v1) {
  150|       |    // Note: the AVX2 variant of pack operates on 128-bit lanes, thus
  151|       |    //       we have to shuffle lanes in order to produce bytes in the
  152|       |    //       correct order.
  153|       |
  154|       |    // get the 0th lanes
  155|  1.70M|    const __m128i lo_0 = _mm256_extracti128_si256(v0, 0);
  156|  1.70M|    const __m128i lo_1 = _mm256_extracti128_si256(v1, 0);
  157|       |
  158|       |    // get the 1st lanes
  159|  1.70M|    const __m128i hi_0 = _mm256_extracti128_si256(v0, 1);
  160|  1.70M|    const __m128i hi_1 = _mm256_extracti128_si256(v1, 1);
  161|       |
  162|       |    // build new vectors (shuffle lanes)
  163|  1.70M|    const __m256i t0 = _mm256_set_m128i(lo_1, lo_0);
  ------------------
  |  |    4|  1.70M|      _mm256_permute2f128_si256(_mm256_castsi128_si256(xmm1),                  \
  |  |    5|  1.70M|                                _mm256_castsi128_si256(xmm2), 2)
  ------------------
  164|  1.70M|    const __m256i t1 = _mm256_set_m128i(hi_1, hi_0);
  ------------------
  |  |    4|  1.70M|      _mm256_permute2f128_si256(_mm256_castsi128_si256(xmm1),                  \
  |  |    5|  1.70M|                                _mm256_castsi128_si256(xmm2), 2)
  ------------------
  165|       |
  166|       |    // pack code units in linear order from v0 and v1
  167|  1.70M|    return _mm256_packus_epi16(t0, t1);
  168|  1.70M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd9simd16x32ItEC2EPKt:
  202|  83.4k|      : chunks{simd16<T>::load(ptr),
  203|  83.4k|               simd16<T>::load(ptr + sizeof(simd16<T>) / sizeof(T))} {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE4loadEPKt:
   66|  3.10M|  static simdutf_really_inline simd16<T> load(const T values[8]) {
   67|  3.10M|    return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(values));
   68|  3.10M|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd9simd16x32ItE10swap_bytesEv:
  229|  82.7k|  simdutf_really_inline void swap_bytes() {
  230|  82.7k|    this->chunks[0] = this->chunks[0].swap_bytes();
  231|  82.7k|    this->chunks[1] = this->chunks[1].swap_bytes();
  232|  82.7k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE10swap_bytesEv:
  139|   165k|  simdutf_really_inline simd16<uint16_t> swap_bytes() const {
  140|   165k|    const __m256i swap = _mm256_setr_epi8(
  141|   165k|        1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17, 16, 19, 18,
  142|   165k|        21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30);
  143|   165k|    return _mm256_shuffle_epi8(*this, swap);
  144|   165k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd9simd16x32ItE5storeEPt:
  205|  82.0k|  simdutf_really_inline void store(T *ptr) const {
  206|  82.0k|    this->chunks[0].store(ptr + sizeof(simd16<T>) * 0 / sizeof(T));
  207|  82.0k|    this->chunks[1].store(ptr + sizeof(simd16<T>) * 1 / sizeof(T));
  208|  82.0k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE5storeEPt:
   76|   164k|  simdutf_really_inline void store(T dst[8]) const {
   77|   164k|    return _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst), *this);
   78|   164k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd14base16_numericItE5splatEt:
   58|   597k|  static simdutf_really_inline simd16<T> splat(T _value) {
   59|   597k|    return _mm256_set1_epi16(_value);
   60|   597k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdeqENS2_6simd16ItEES4_:
   26|  2.68k|                                               const simd16<T> rhs) {
   27|  2.68k|    return _mm256_cmpeq_epi16(lhs, rhs);
   28|  2.68k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16IbEC2EDv4_x:
   45|  2.68k|  simdutf_really_inline simd16(const __m256i _value) : base16<bool>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6base16IbNS2_6simd16IbEEEC2EDv4_x:
   20|  2.68k|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd9simd16x32IbEC2ENS2_6simd16IbEES6_:
  200|  1.34k|      : chunks{chunk0, chunk1} {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd9simd16x32IbE10to_bitmaskEv:
  210|  1.34k|  simdutf_really_inline uint64_t to_bitmask() const {
  211|  1.34k|    uint64_t r_lo = uint32_t(this->chunks[0].to_bitmask());
  212|  1.34k|    uint64_t r_hi = this->chunks[1].to_bitmask();
  213|  1.34k|    return r_lo | (r_hi << 32);
  214|  1.34k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16IbE10to_bitmaskEv:
   50|  2.68k|  simdutf_really_inline bitmask_type to_bitmask() const {
   51|  2.68k|    return _mm256_movemask_epi8(*this);
   52|  2.68k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE3shrILi8EEES4_v:
  134|  2.21M|  template <int N> simdutf_really_inline simd16<uint16_t> shr() const {
  135|  2.21M|    return simd16<uint16_t>(_mm256_srli_epi16(*this, N));
  136|  2.21M|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd9simd16x32ItE4lteqEt:
  239|  1.34k|  simdutf_really_inline uint64_t lteq(const T m) const {
  240|  1.34k|    const simd16<T> mask = simd16<T>::splat(m);
  241|  1.34k|    return simd16x32<bool>(this->chunks[0] <= mask, this->chunks[1] <= mask)
  242|  1.34k|        .to_bitmask();
  243|  1.34k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEleES4_:
  117|  2.68k|  operator<=(const simd16<uint16_t> other) const {
  118|  2.68k|    return other.max_val(*this) == other;
  119|  2.68k|  }
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd16ItE7max_valES4_:
  108|  2.68k|  max_val(const simd16<uint16_t> other) const {
  109|  2.68k|    return _mm256_max_epu16(*this, other);
  110|  2.68k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEC2EPKDs:
  104|  2.93M|      : simd16(load(reinterpret_cast<const uint16_t *>(values))) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd16ItEC2Et:
  100|   596k|  simdutf_really_inline simd16(uint16_t _value) : simd16(splat(_value)) {}

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd32IjE5splatEj:
   46|    672|  simdutf_really_inline static simd32<uint32_t> splat(uint32_t v) {
   47|    672|    return _mm256_set1_epi32(v);
   48|    672|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd32IjEC2EDv4_x:
    9|  1.41M|  simdutf_really_inline simd32(const __m256i v) : value(v) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd32IjE4zeroEv:
   42|    448|  simdutf_really_inline static simd32<uint32_t> zero() {
   43|    448|    return _mm256_setzero_si256();
   44|    448|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd32IjEC2IDiEEPKT_:
   13|   352k|      : value(_mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr))) {}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd32IjE10swap_bytesEv:
   27|   352k|  simdutf_really_inline simd32<uint32_t> swap_bytes() const {
   28|   352k|    const __m256i shuffle =
   29|   352k|        _mm256_setr_epi8(3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 15, 14, 13, 12,
   30|   352k|                         3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 15, 14, 13, 12);
   31|       |
   32|   352k|    return _mm256_shuffle_epi8(value, shuffle);
   33|   352k|  }
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd3maxENS2_6simd32IjEES4_:
   80|   705k|                                           const simd32<uint32_t> b) {
   81|   705k|  return _mm256_max_epu32(a.value, b.value);
   82|   705k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdplENS2_6simd32IjEES4_:
   90|   352k|                                                 const simd32<uint32_t> b) {
   91|   352k|  return _mm256_add_epi32(a.value, b.value);
   92|   352k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdgtENS2_6simd32IjEES4_:
  109|    370|                                             const simd32<uint32_t> b) {
  110|    370|  return !(b >= a);
  111|    370|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdntENS2_6simd32IbEE:
  104|    370|simdutf_really_inline simd32<bool> operator!(const simd32<bool> v) {
  105|    370|  return _mm256_xor_si256(v.value, _mm256_set1_epi8(-1));
  106|    370|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simd6simd32IbEC2EDv4_x:
   59|    740|  simdutf_really_inline simd32(const __m256i v) : value(v) {}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_14simdgeENS2_6simd32IjEES4_:
  100|    370|                                              const simd32<uint32_t> b) {
  101|    370|  return _mm256_cmpeq_epi32(_mm256_max_epu32(a.value, b.value), a.value);
  102|    370|}
simdutf.cpp:_ZNK7simdutf7haswell12_GLOBAL__N_14simd6simd32IbE3anyEv:
   61|    370|  simdutf_really_inline bool any() const {
   62|    370|    return _mm256_movemask_epi8(value) != 0;
   63|    370|  }

_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) {}

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_115trailing_zeroesEm:
   20|    338|simdutf_really_inline int trailing_zeroes(uint64_t input_num) {
   21|       |  #if SIMDUTF_REGULAR_VISUAL_STUDIO
   22|       |  unsigned long ret;
   23|       |  _BitScanForward64(&ret, input_num);
   24|       |  return (int)ret;
   25|       |  #else  // SIMDUTF_REGULAR_VISUAL_STUDIO
   26|    338|  return __builtin_ctzll(input_num);
   27|    338|  #endif // SIMDUTF_REGULAR_VISUAL_STUDIO
   28|    338|}

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

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Ev:
  183|  3.79k|  simdutf_really_inline simd8() : base8_numeric<uint8_t>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhEC2Ev:
  118|  3.79k|  simdutf_really_inline base8_numeric() : base8<T>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2Ev:
   68|  3.79k|  simdutf_really_inline base8() : base<simd8<T>>() {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2Ev:
   13|  3.79k|  simdutf_really_inline base() : value{__m128i()} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd8simd8x64IhE9reduce_orEv:
  290|   721k|  simdutf_really_inline simd8<T> reduce_or() const {
  291|   721k|    return (this->chunks[0] | this->chunks[1]) |
  292|   721k|           (this->chunks[2] | this->chunks[3]);
  293|   721k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEorES5_:
   42|  4.25M|  simdutf_really_inline Child operator|(const Child other) const {
   43|  4.25M|    return _mm_or_si128(*this, other);
   44|  4.25M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2EDv2_x:
  185|  34.0M|      : base8_numeric<uint8_t>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhEC2EDv2_x:
  120|  34.0M|      : base8<T>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEEC2EDv2_x:
   69|  34.0M|  simdutf_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEC2EDv2_x:
   16|  34.0M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE8is_asciiEv:
  228|   721k|  simdutf_really_inline bool is_ascii() const {
  229|   721k|    return _mm_movemask_epi8(*this) == 0;
  230|   721k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEoRES5_:
   51|  1.25M|  simdutf_really_inline Child &operator|=(const Child other) {
   52|  1.25M|    auto this_cast = static_cast<Child *>(this);
   53|  1.25M|    *this_cast = *this_cast | other;
   54|  1.25M|    return *this_cast;
   55|  1.25M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi1EEENS4_IhEES8_:
   79|   834k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|   834k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE3shrILi4EEES4_v:
  238|  1.66M|  template <int N> simdutf_really_inline simd8<uint8_t> shr() const {
  239|  1.66M|    return simd8<uint8_t>(_mm_srli_epi16(*this, N)) & uint8_t(0xFFu >> N);
  240|  1.66M|  }
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|  2.50M|            L replace15) const {
  152|  2.50M|    return lookup_16(simd8<L>::repeat_16(
  153|  2.50M|        replace0, replace1, replace2, replace3, replace4, replace5, replace6,
  154|  2.50M|        replace7, replace8, replace9, replace10, replace11, replace12,
  155|  2.50M|        replace13, replace14, replace15));
  156|  2.50M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE9lookup_16IhEENS2_5simd8IT_EES8_:
  142|  2.50M|  simdutf_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
  143|  2.50M|    return _mm_shuffle_epi8(lookup_table, *this);
  144|  2.50M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE9repeat_16Ehhhhhhhhhhhhhhhh:
  113|  2.50M|                                                  T v14, T v15) {
  114|  2.50M|    return simd8<T>(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
  115|  2.50M|                    v14, v15);
  116|  2.50M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Ehhhhhhhhhhhhhhhh:
  196|  2.50M|      : simd8(_mm_setr_epi8(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
  197|  2.50M|                            v12, v13, v14, v15)) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2Eh:
  188|  5.00M|  simdutf_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi2EEENS4_IhEES8_:
   79|   834k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|   834k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5base8IhNS2_5simd8IbEEE4prevILi3EEENS4_IhEES8_:
   79|   834k|  simdutf_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
   80|       |    return _mm_alignr_epi8(*this, prev_chunk, 16 - N);
   81|   834k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE14saturating_subES4_:
  201|  1.87M|  saturating_sub(const simd8<uint8_t> other) const {
  202|  1.87M|    return _mm_subs_epu8(*this, other);
  203|  1.87M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IbEC2EDv2_x:
   91|  3.08M|  simdutf_really_inline simd8(const __m128i _value) : base8<bool>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5base8IbNS2_5simd8IbEEEC2EDv2_x:
   69|  3.08M|  simdutf_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEC2EDv2_x:
   16|  3.08M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IbEEEcvRKDv2_xEv:
   18|  3.08M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEeoES5_:
   48|   834k|  simdutf_really_inline Child operator^(const Child other) const {
   49|   834k|    return _mm_xor_si128(*this, other);
   50|   834k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd5simd8IhEC2EPKh:
  190|   208k|  simdutf_really_inline simd8(const uint8_t *values) : simd8(load(values)) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE4loadEPKh:
  106|  3.09M|  static simdutf_really_inline simd8<T> load(const T values[16]) {
  107|  3.09M|    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
  108|  3.09M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE7gt_bitsES4_:
  212|   208k|  gt_bits(const simd8<uint8_t> other) const {
  213|   208k|    return this->saturating_sub(other);
  214|   208k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEC2EDv2_x:
   16|  8.18M|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEcvRKDv2_xEv:
   18|  8.71M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IbE10to_bitmaskEv:
   95|  2.25M|  simdutf_really_inline int to_bitmask() const {
   96|  2.25M|    return _mm_movemask_epi8(*this);
   97|  2.25M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE21any_bits_set_anywhereEv:
  235|  1.26k|  simdutf_really_inline bool any_bits_set_anywhere() const {
  236|  1.26k|    return !bits_not_set_anywhere();
  237|  1.26k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd5simd8IhE21bits_not_set_anywhereEv:
  232|  1.26k|  simdutf_really_inline bool bits_not_set_anywhere() const {
  233|  1.26k|    return _mm_testz_si128(*this, *this);
  234|  1.26k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd8simd8x64IhE8is_asciiEv:
  295|  95.5k|  simdutf_really_inline bool is_ascii() const {
  296|  95.5k|    return this->reduce_or().is_ascii();
  297|  95.5k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEC2EDv2_x:
   16|  5.37k|  simdutf_really_inline base(const __m128i _value) : value(_value) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16IbEEEcvRKDv2_xEv:
   18|  5.37k|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd13base8_numericIhE5splatEh:
  102|  5.01M|  static simdutf_really_inline simd8<T> splat(T _value) {
  103|  5.01M|    return _mm_set1_epi8(_value);
  104|  5.01M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEcvRKDv2_xEv:
   18|  49.0M|  simdutf_really_inline operator const __m128i &() const { return this->value; }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdeqENS2_5simd8IhEES4_:
   72|  2.25M|                                               const simd8<T> rhs) {
   73|  2.25M|    return _mm_cmpeq_epi8(lhs, rhs);
   74|  2.25M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_5simd8IhEEEanES5_:
   45|  7.25M|  simdutf_really_inline Child operator&(const Child other) const {
   46|  7.25M|    return _mm_and_si128(*this, other);
   47|  7.25M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd8simd8x64IhEC2EPKh:
  270|   721k|      : chunks{simd8<T>::load(ptr),
  271|   721k|               simd8<T>::load(ptr + sizeof(simd8<T>) / sizeof(T)),
  272|   721k|               simd8<T>::load(ptr + 2 * sizeof(simd8<T>) / sizeof(T)),
  273|   721k|               simd8<T>::load(ptr + 3 * sizeof(simd8<T>) / sizeof(T))} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd4baseINS2_6simd16ItEEEanES5_:
   45|  1.03M|  simdutf_really_inline Child operator&(const Child other) const {
   46|  1.03M|    return _mm_and_si128(*this, other);
   47|  1.03M|  }

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEC2EDv2_x:
   79|  8.18M|      : base16_numeric<uint16_t>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItEC2EDv2_x:
   54|  8.18M|      : base16<T>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6base16ItNS2_6simd16IbEEEC2EDv2_x:
    8|  8.18M|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE4packERKS4_S6_:
  130|  1.74M|                                                   const simd16<uint16_t> &v1) {
  131|  1.74M|    return _mm_packus_epi16(v0, v1);
  132|  1.74M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd9simd16x32ItEC2EPKt:
  164|  83.4k|      : chunks{simd16<T>::load(ptr),
  165|  83.4k|               simd16<T>::load(ptr + sizeof(simd16<T>) / sizeof(T)),
  166|  83.4k|               simd16<T>::load(ptr + 2 * sizeof(simd16<T>) / sizeof(T)),
  167|  83.4k|               simd16<T>::load(ptr + 3 * sizeof(simd16<T>) / sizeof(T))} {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE4loadEPKt:
   47|  2.88M|  static simdutf_really_inline simd16<T> load(const T values[8]) {
   48|  2.88M|    return _mm_loadu_si128(reinterpret_cast<const __m128i *>(values));
   49|  2.88M|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd9simd16x32ItE10swap_bytesEv:
  200|  82.7k|  simdutf_really_inline void swap_bytes() {
  201|  82.7k|    this->chunks[0] = this->chunks[0].swap_bytes();
  202|  82.7k|    this->chunks[1] = this->chunks[1].swap_bytes();
  203|  82.7k|    this->chunks[2] = this->chunks[2].swap_bytes();
  204|  82.7k|    this->chunks[3] = this->chunks[3].swap_bytes();
  205|  82.7k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE10swap_bytesEv:
  121|   330k|  simdutf_really_inline simd16<uint16_t> swap_bytes() const {
  122|   330k|    const __m128i swap =
  123|   330k|        _mm_setr_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14);
  124|   330k|    return _mm_shuffle_epi8(*this, swap);
  125|   330k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd9simd16x32ItE5storeEPt:
  169|  82.0k|  simdutf_really_inline void store(T *ptr) const {
  170|  82.0k|    this->chunks[0].store(ptr + sizeof(simd16<T>) * 0 / sizeof(T));
  171|  82.0k|    this->chunks[1].store(ptr + sizeof(simd16<T>) * 1 / sizeof(T));
  172|  82.0k|    this->chunks[2].store(ptr + sizeof(simd16<T>) * 2 / sizeof(T));
  173|  82.0k|    this->chunks[3].store(ptr + sizeof(simd16<T>) * 3 / sizeof(T));
  174|  82.0k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE5storeEPt:
   57|   328k|  simdutf_really_inline void store(T dst[8]) const {
   58|   328k|    return _mm_storeu_si128(reinterpret_cast<__m128i *>(dst), *this);
   59|   328k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd14base16_numericItE5splatEt:
   41|   517k|  static simdutf_really_inline simd16<T> splat(T _value) {
   42|   517k|    return _mm_set1_epi16(_value);
   43|   517k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdeqENS2_6simd16ItEES4_:
   11|  5.37k|                                               const simd16<T> rhs) {
   12|  5.37k|    return _mm_cmpeq_epi16(lhs, rhs);
   13|  5.37k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16IbEC2EDv2_x:
   28|  5.37k|  simdutf_really_inline simd16(const __m128i _value) : base16<bool>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6base16IbNS2_6simd16IbEEEC2EDv2_x:
    8|  5.37k|      : base<simd16<T>>(_value) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd9simd16x32IbEC2ENS2_6simd16IbEES6_S6_S6_:
  162|  1.34k|      : chunks{chunk0, chunk1, chunk2, chunk3} {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd9simd16x32IbE10to_bitmaskEv:
  192|  1.34k|  simdutf_really_inline uint64_t to_bitmask() const {
  193|  1.34k|    uint64_t r0 = uint32_t(this->chunks[0].to_bitmask());
  194|  1.34k|    uint64_t r1 = this->chunks[1].to_bitmask();
  195|  1.34k|    uint64_t r2 = this->chunks[2].to_bitmask();
  196|  1.34k|    uint64_t r3 = this->chunks[3].to_bitmask();
  197|  1.34k|    return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48);
  198|  1.34k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16IbE10to_bitmaskEv:
   33|  5.37k|  simdutf_really_inline int to_bitmask() const {
   34|  5.37k|    return _mm_movemask_epi8(*this);
   35|  5.37k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE3shrILi8EEES4_v:
  116|  2.46M|  template <int N> simdutf_really_inline simd16<uint16_t> shr() const {
  117|  2.46M|    return simd16<uint16_t>(_mm_srli_epi16(*this, N));
  118|  2.46M|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd9simd16x32ItE4lteqEt:
  207|  1.34k|  simdutf_really_inline uint64_t lteq(const T m) const {
  208|  1.34k|    const simd16<T> mask = simd16<T>::splat(m);
  209|  1.34k|    return simd16x32<bool>(this->chunks[0] <= mask, this->chunks[1] <= mask,
  210|  1.34k|                           this->chunks[2] <= mask, this->chunks[3] <= mask)
  211|  1.34k|        .to_bitmask();
  212|  1.34k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEleES4_:
  100|  5.37k|  operator<=(const simd16<uint16_t> other) const {
  101|  5.37k|    return other.max_val(*this) == other;
  102|  5.37k|  }
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd16ItE7max_valES4_:
   90|  5.37k|  max_val(const simd16<uint16_t> other) const {
   91|  5.37k|    return _mm_max_epu16(*this, other);
   92|  5.37k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEC2EPKDs:
   86|  2.55M|      : simd16(load(reinterpret_cast<const uint16_t *>(values))) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd16ItEC2Et:
   82|   516k|  simdutf_really_inline simd16(uint16_t _value) : simd16(splat(_value)) {}

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd32IjE5splatEj:
   56|    672|  simdutf_really_inline static simd32<uint32_t> splat(uint32_t v) {
   57|    672|    return _mm_set1_epi32(v);
   58|    672|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd32IjEC2EDv2_x:
    9|  2.82M|  simdutf_really_inline simd32(const __m128i v) : value(v) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd32IjE4zeroEv:
   52|    448|  simdutf_really_inline static simd32<uint32_t> zero() {
   53|    448|    return _mm_setzero_si128();
   54|    448|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd32IjEC2IDiEEPKT_:
   13|   706k|      : value(_mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr))) {}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd32IjE10swap_bytesEv:
   22|   706k|  simdutf_really_inline simd32<uint32_t> swap_bytes() const {
   23|   706k|    const __m128i shuffle =
   24|   706k|        _mm_setr_epi8(3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 15, 14, 13, 12);
   25|       |
   26|   706k|    return _mm_shuffle_epi8(value, shuffle);
   27|   706k|  }
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd3maxENS2_6simd32IjEES4_:
   94|  1.41M|                                           const simd32<uint32_t> b) {
   95|  1.41M|  return _mm_max_epu32(a.value, b.value);
   96|  1.41M|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdplENS2_6simd32IjEES4_:
  119|   706k|                                                 const simd32<uint32_t> b) {
  120|   706k|  return _mm_add_epi32(a.value, b.value);
  121|   706k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdgtENS2_6simd32IjEES4_:
  143|    356|                                             const simd32<uint32_t> b) {
  144|    356|  return !(b >= a);
  145|    356|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdntENS2_6simd32IbEE:
  138|    356|simdutf_really_inline simd32<bool> operator!(const simd32<bool> v) {
  139|    356|  return _mm_xor_si128(v.value, _mm_set1_epi8(-1));
  140|    356|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simd6simd32IbEC2EDv2_x:
   69|    712|  simdutf_really_inline simd32(const __m128i v) : value(v) {}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_14simdgeENS2_6simd32IjEES4_:
  134|    356|                                              const simd32<uint32_t> b) {
  135|    356|  return _mm_cmpeq_epi32(_mm_max_epu32(a.value, b.value), a.value);
  136|    356|}
simdutf.cpp:_ZNK7simdutf8westmere12_GLOBAL__N_14simd6simd32IbE3anyEv:
   71|    356|  simdutf_really_inline bool any() const {
   72|    356|    return _mm_movemask_epi8(value) != 0;
   73|    356|  }

_ZNK7simdutf8westmere14implementation16detect_encodingsEPKcm:
  157|    660|                                 size_t length) const noexcept {
  158|       |  // If there is a BOM, then we trust it.
  159|    660|  auto bom_encoding = simdutf::BOM::check_bom(input, length);
  160|    660|  if (bom_encoding != encoding_type::unspecified) {
  ------------------
  |  Branch (160:7): [True: 41, False: 619]
  ------------------
  161|     41|    return bom_encoding;
  162|     41|  }
  163|       |
  164|    619|  int out = 0;
  165|    619|  uint32_t utf16_err = (length % 2);
  166|    619|  uint32_t utf32_err = (length % 4);
  167|    619|  uint32_t ends_with_high = 0;
  168|    619|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
  169|    619|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
  170|    619|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
  171|    619|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
  172|    619|  const __m128i standardmax = _mm_set1_epi32(0x10ffff);
  173|    619|  const __m128i offset = _mm_set1_epi32(0xffff2000);
  174|    619|  const __m128i standardoffsetmax = _mm_set1_epi32(0xfffff7ff);
  175|    619|  __m128i currentmax = _mm_setzero_si128();
  176|    619|  __m128i currentoffsetmax = _mm_setzero_si128();
  177|       |
  178|    619|  utf8_checker c{};
  179|    619|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
  180|   236k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (180:10): [True: 235k, False: 619]
  ------------------
  181|   235k|    simd::simd8x64<uint8_t> in(reader.full_block());
  182|       |    // utf8 checks
  183|   235k|    c.check_next_input(in);
  184|       |
  185|       |    // utf16le checks
  186|   235k|    auto in0 = simd16<uint16_t>(in.chunks[0]);
  187|   235k|    auto in1 = simd16<uint16_t>(in.chunks[1]);
  188|   235k|    const auto t0 = in0.shr<8>();
  189|   235k|    const auto t1 = in1.shr<8>();
  190|   235k|    const auto packed1 = simd16<uint16_t>::pack(t0, t1);
  191|   235k|    auto in2 = simd16<uint16_t>(in.chunks[2]);
  192|   235k|    auto in3 = simd16<uint16_t>(in.chunks[3]);
  193|   235k|    const auto t2 = in2.shr<8>();
  194|   235k|    const auto t3 = in3.shr<8>();
  195|   235k|    const auto packed2 = simd16<uint16_t>::pack(t2, t3);
  196|       |
  197|   235k|    const auto surrogates_wordmask_lo = (packed1 & v_f8) == v_d8;
  198|   235k|    const auto surrogates_wordmask_hi = (packed2 & v_f8) == v_d8;
  199|   235k|    const uint32_t surrogates_bitmask =
  200|   235k|        (surrogates_wordmask_hi.to_bitmask() << 16) |
  201|   235k|        surrogates_wordmask_lo.to_bitmask();
  202|   235k|    const auto vL_lo = (packed1 & v_fc) == v_dc;
  203|   235k|    const auto vL_hi = (packed2 & v_fc) == v_dc;
  204|   235k|    const uint32_t L = (vL_hi.to_bitmask() << 16) | vL_lo.to_bitmask();
  205|   235k|    const uint32_t H = L ^ surrogates_bitmask;
  206|   235k|    utf16_err |= (((H << 1) | ends_with_high) != L);
  207|   235k|    ends_with_high = (H & 0x80000000) != 0;
  208|       |
  209|       |    // utf32le checks
  210|   235k|    currentmax = _mm_max_epu32(in.chunks[0], currentmax);
  211|   235k|    currentoffsetmax =
  212|   235k|        _mm_max_epu32(_mm_add_epi32(in.chunks[0], offset), currentoffsetmax);
  213|   235k|    currentmax = _mm_max_epu32(in.chunks[1], currentmax);
  214|   235k|    currentoffsetmax =
  215|   235k|        _mm_max_epu32(_mm_add_epi32(in.chunks[1], offset), currentoffsetmax);
  216|   235k|    currentmax = _mm_max_epu32(in.chunks[2], currentmax);
  217|   235k|    currentoffsetmax =
  218|   235k|        _mm_max_epu32(_mm_add_epi32(in.chunks[2], offset), currentoffsetmax);
  219|   235k|    currentmax = _mm_max_epu32(in.chunks[3], currentmax);
  220|   235k|    currentoffsetmax =
  221|   235k|        _mm_max_epu32(_mm_add_epi32(in.chunks[3], offset), currentoffsetmax);
  222|       |
  223|   235k|    reader.advance();
  224|   235k|  }
  225|       |
  226|    619|  uint8_t block[64]{};
  227|    619|  size_t idx = reader.block_index();
  228|    619|  std::memcpy(block, &input[idx], length - idx);
  229|    619|  simd::simd8x64<uint8_t> in(block);
  230|    619|  c.check_next_input(in);
  231|       |
  232|       |  // utf16le last block check
  233|    619|  auto in0 = simd16<uint16_t>(in.chunks[0]);
  234|    619|  auto in1 = simd16<uint16_t>(in.chunks[1]);
  235|    619|  const auto t0 = in0.shr<8>();
  236|    619|  const auto t1 = in1.shr<8>();
  237|    619|  const auto packed1 = simd16<uint16_t>::pack(t0, t1);
  238|    619|  auto in2 = simd16<uint16_t>(in.chunks[2]);
  239|    619|  auto in3 = simd16<uint16_t>(in.chunks[3]);
  240|    619|  const auto t2 = in2.shr<8>();
  241|    619|  const auto t3 = in3.shr<8>();
  242|    619|  const auto packed2 = simd16<uint16_t>::pack(t2, t3);
  243|       |
  244|    619|  const auto surrogates_wordmask_lo = (packed1 & v_f8) == v_d8;
  245|    619|  const auto surrogates_wordmask_hi = (packed2 & v_f8) == v_d8;
  246|    619|  const uint32_t surrogates_bitmask =
  247|    619|      (surrogates_wordmask_hi.to_bitmask() << 16) |
  248|    619|      surrogates_wordmask_lo.to_bitmask();
  249|    619|  const auto vL_lo = (packed1 & v_fc) == v_dc;
  250|    619|  const auto vL_hi = (packed2 & v_fc) == v_dc;
  251|    619|  const uint32_t L = (vL_hi.to_bitmask() << 16) | vL_lo.to_bitmask();
  252|    619|  const uint32_t H = L ^ surrogates_bitmask;
  253|    619|  utf16_err |= (((H << 1) | ends_with_high) != L);
  254|       |  // this is required to check for last byte ending in high and end of input
  255|       |  // is reached
  256|    619|  ends_with_high = (H & 0x80000000) != 0;
  257|    619|  utf16_err |= ends_with_high;
  258|       |
  259|       |  // utf32le last block check
  260|    619|  currentmax = _mm_max_epu32(in.chunks[0], currentmax);
  261|    619|  currentoffsetmax =
  262|    619|      _mm_max_epu32(_mm_add_epi32(in.chunks[0], offset), currentoffsetmax);
  263|    619|  currentmax = _mm_max_epu32(in.chunks[1], currentmax);
  264|    619|  currentoffsetmax =
  265|    619|      _mm_max_epu32(_mm_add_epi32(in.chunks[1], offset), currentoffsetmax);
  266|    619|  currentmax = _mm_max_epu32(in.chunks[2], currentmax);
  267|    619|  currentoffsetmax =
  268|    619|      _mm_max_epu32(_mm_add_epi32(in.chunks[2], offset), currentoffsetmax);
  269|    619|  currentmax = _mm_max_epu32(in.chunks[3], currentmax);
  270|    619|  currentoffsetmax =
  271|    619|      _mm_max_epu32(_mm_add_epi32(in.chunks[3], offset), currentoffsetmax);
  272|       |
  273|    619|  reader.advance();
  274|       |
  275|    619|  c.check_eof();
  276|    619|  bool is_valid_utf8 = !c.errors();
  277|    619|  __m128i is_zero =
  278|    619|      _mm_xor_si128(_mm_max_epu32(currentmax, standardmax), standardmax);
  279|    619|  utf32_err |= (_mm_test_all_zeros(is_zero, is_zero) == 0);
  280|       |
  281|    619|  is_zero = _mm_xor_si128(_mm_max_epu32(currentoffsetmax, standardoffsetmax),
  282|    619|                          standardoffsetmax);
  283|    619|  utf32_err |= (_mm_test_all_zeros(is_zero, is_zero) == 0);
  284|    619|  if (is_valid_utf8) {
  ------------------
  |  Branch (284:7): [True: 89, False: 530]
  ------------------
  285|     89|    out |= encoding_type::UTF8;
  286|     89|  }
  287|    619|  if (utf16_err == 0) {
  ------------------
  |  Branch (287:7): [True: 216, False: 403]
  ------------------
  288|    216|    out |= encoding_type::UTF16_LE;
  289|    216|  }
  290|    619|  if (utf32_err == 0) {
  ------------------
  |  Branch (290:7): [True: 69, False: 550]
  ------------------
  291|     69|    out |= encoding_type::UTF32_LE;
  292|     69|  }
  293|    619|  return out;
  294|    660|}
_ZNK7simdutf8westmere14implementation13validate_utf8EPKcm:
  299|    645|implementation::validate_utf8(const char *buf, size_t len) const noexcept {
  300|    645|  return westmere::utf8_validation::generic_validate_utf8(buf, len);
  301|    645|}
_ZNK7simdutf8westmere14implementation14validate_asciiEPKcm:
  313|    201|implementation::validate_ascii(const char *buf, size_t len) const noexcept {
  314|    201|  return westmere::ascii_validation::generic_validate_ascii(buf, len);
  315|    201|}
_ZNK7simdutf8westmere14implementation26validate_ascii_with_errorsEPKcm:
  318|    283|    const char *buf, size_t len) const noexcept {
  319|    283|  return westmere::ascii_validation::generic_validate_ascii_with_errors(buf,
  320|    283|                                                                        len);
  321|    283|}
_ZNK7simdutf8westmere14implementation25validate_utf16le_as_asciiEPKDsm:
  327|    225|                                          size_t len) const noexcept {
  328|    225|  return westmere::utf16::validate_utf16_as_ascii_with_errors<
  329|    225|             endianness::LITTLE>(buf, len)
  330|    225|             .error == SUCCESS;
  331|    225|}
_ZNK7simdutf8westmere14implementation25validate_utf16be_as_asciiEPKDsm:
  335|    225|                                          size_t len) const noexcept {
  336|    225|  return westmere::utf16::validate_utf16_as_ascii_with_errors<endianness::BIG>(
  337|    225|             buf, len)
  338|    225|             .error == SUCCESS;
  339|    225|}
_ZNK7simdutf8westmere14implementation16validate_utf16leEPKDsm:
  345|  1.12k|                                 size_t len) const noexcept {
  346|  1.12k|  if (simdutf_unlikely(len == 0)) {
  ------------------
  |  |   93|  1.12k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 3, False: 1.12k]
  |  |  ------------------
  ------------------
  347|       |    // empty input is valid UTF-16. protect the implementation from
  348|       |    // handling nullptr
  349|      3|    return true;
  350|      3|  }
  351|  1.12k|  const auto res =
  352|  1.12k|      westmere::utf16::validate_utf16_with_errors<endianness::LITTLE>(buf, len);
  353|  1.12k|  if (res.is_err()) {
  ------------------
  |  Branch (353:7): [True: 106, False: 1.01k]
  ------------------
  354|    106|    return false;
  355|    106|  }
  356|       |
  357|  1.01k|  if (res.count == len)
  ------------------
  |  Branch (357:7): [True: 0, False: 1.01k]
  ------------------
  358|      0|    return true;
  359|       |
  360|  1.01k|  return scalar::utf16::validate<endianness::LITTLE>(buf + res.count,
  361|  1.01k|                                                     len - res.count);
  362|  1.01k|}
_ZNK7simdutf8westmere14implementation16validate_utf16beEPKDsm:
  368|    711|                                 size_t len) const noexcept {
  369|    711|  if (simdutf_unlikely(len == 0)) {
  ------------------
  |  |   93|    711|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 3, False: 708]
  |  |  ------------------
  ------------------
  370|       |    // empty input is valid UTF-16. protect the implementation from
  371|       |    // handling nullptr
  372|      3|    return true;
  373|      3|  }
  374|    708|  const auto res =
  375|    708|      westmere::utf16::validate_utf16_with_errors<endianness::BIG>(buf, len);
  376|    708|  if (res.is_err()) {
  ------------------
  |  Branch (376:7): [True: 0, False: 708]
  ------------------
  377|      0|    return false;
  378|      0|  }
  379|       |
  380|    708|  if (res.count == len)
  ------------------
  |  Branch (380:7): [True: 0, False: 708]
  ------------------
  381|      0|    return true;
  382|       |
  383|    708|  return scalar::utf16::validate<endianness::BIG>(buf + res.count,
  384|    708|                                                  len - res.count);
  385|    708|}
_ZNK7simdutf8westmere14implementation22to_well_formed_utf16leEPKDsmPDs:
  415|    687|                                            char16_t *output) const noexcept {
  416|    687|  return utf16fix_sse<endianness::LITTLE>(input, len, output);
  417|    687|}
_ZNK7simdutf8westmere14implementation22to_well_formed_utf16beEPKDsmPDs:
  420|    687|                                            char16_t *output) const noexcept {
  421|    687|  return utf16fix_sse<endianness::BIG>(input, len, output);
  422|    687|}
_ZNK7simdutf8westmere14implementation14validate_utf32EPKDim:
  427|    224|implementation::validate_utf32(const char32_t *buf, size_t len) const noexcept {
  428|    224|  return utf32::validate(buf, len);
  429|    224|}
_ZNK7simdutf8westmere14implementation23change_endianness_utf16EPKDsmPDs:
 1127|    133|                                             char16_t *output) const noexcept {
 1128|    133|  utf16::change_endianness_utf16(input, length, output);
 1129|    133|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_18is_asciiERKNS1_4simd8simd8x64IhEE:
   13|   625k|simdutf_really_inline bool is_ascii(const simd8x64<uint8_t> &input) {
   14|   625k|  return input.reduce_or().is_ascii();
   15|   625k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_124must_be_2_3_continuationENS1_4simd5simd8IhEES4_:
   22|   834k|                         const simd8<uint8_t> prev3) {
   23|   834k|  simd8<uint8_t> is_third_byte =
   24|   834k|      prev2.saturating_sub(0xe0u - 0x80); // Only 111_____ will be >= 0x80
   25|   834k|  simd8<uint8_t> is_fourth_byte =
   26|   834k|      prev3.saturating_sub(0xf0u - 0x80); // Only 1111____ will be >= 0x80
   27|   834k|  return simd8<bool>(is_third_byte | is_fourth_byte);
   28|   834k|}

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE0EEEvPKDsmPDs:
   53|    687|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
   54|    687|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   55|    687|  size_t i;
   56|    687|  if (n < 9) {
  ------------------
  |  Branch (56:7): [True: 159, False: 528]
  ------------------
   57|    159|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
   58|    159|    return;
   59|    159|  }
   60|       |
   61|    528|  out[0] =
   62|    528|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (62:7): [True: 63, False: 465]
  ------------------
   63|       |
   64|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
   65|    528|  if (in == out) {
  ------------------
  |  Branch (65:7): [True: 0, False: 528]
  ------------------
   66|      0|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (66:17): [True: 0, False: 0]
  ------------------
   67|      0|      utf16fix_block_sse<big_endian, true>(out + i, in + i);
   68|      0|    }
   69|       |
   70|      0|    utf16fix_block_sse<big_endian, true>(out + n - 8, in + n - 8);
   71|    528|  } else {
   72|  1.03M|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (72:17): [True: 1.03M, False: 528]
  ------------------
   73|  1.03M|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
   74|  1.03M|    }
   75|       |
   76|    528|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
   77|    528|  }
   78|       |
   79|    528|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (79:16): [True: 67, False: 461]
  ------------------
   80|    528|                   ? replacement
   81|    528|                   : out[n - 1];
   82|    528|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDs:
   11|  1.03M|                                              const char16_t *in) {
   12|  1.03M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   13|  1.03M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   14|  1.03M|  };
   15|  1.03M|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   16|       |
   17|  1.03M|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   18|  1.03M|  __m128i illseq, lb_illseq, block_illseq;
   19|       |
   20|  1.03M|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   21|  1.03M|  block = _mm_loadu_si128((const __m128i *)in);
   22|  1.03M|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   23|  1.03M|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   24|  1.03M|  lb_is_high =
   25|  1.03M|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   26|  1.03M|  block_is_low =
   27|  1.03M|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   28|       |
   29|  1.03M|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   30|  1.03M|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (30:7): [True: 70.2k, False: 962k]
  ------------------
   31|  70.2k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  70.2k|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   35|  70.2k|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   36|  70.2k|                                _mm_bsrli_si128(lb_illseq, 2));
   37|       |
   38|       |    /* fix illegal sequencing in the lookback */
   39|  70.2k|    lb = _mm_cvtsi128_si32(lb_illseq);
   40|  70.2k|    lb = (lb & replacement) | (~lb & out[-1]);
   41|  70.2k|    out[-1] = char16_t(lb);
   42|       |    /* fix illegal sequencing in the main block */
   43|  70.2k|    block =
   44|  70.2k|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
   45|  70.2k|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
   46|  70.2k|    _mm_storeu_si128((__m128i *)out, block);
   47|   962k|  } else if (!in_place) {
  ------------------
  |  Branch (47:14): [True: 962k, Folded]
  ------------------
   48|   962k|    _mm_storeu_si128((__m128i *)out, block);
   49|   962k|  }
   50|  1.03M|}
simdutf.cpp:_ZZN7simdutf8westmere12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDsENKUltE_clEt:
   12|  4.13M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   13|  4.13M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   14|  4.13M|  };
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE1EEEvPKDsmPDs:
   53|    687|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
   54|    687|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   55|    687|  size_t i;
   56|    687|  if (n < 9) {
  ------------------
  |  Branch (56:7): [True: 159, False: 528]
  ------------------
   57|    159|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
   58|    159|    return;
   59|    159|  }
   60|       |
   61|    528|  out[0] =
   62|    528|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (62:7): [True: 63, False: 465]
  ------------------
   63|       |
   64|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
   65|    528|  if (in == out) {
  ------------------
  |  Branch (65:7): [True: 0, False: 528]
  ------------------
   66|      0|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (66:17): [True: 0, False: 0]
  ------------------
   67|      0|      utf16fix_block_sse<big_endian, true>(out + i, in + i);
   68|      0|    }
   69|       |
   70|      0|    utf16fix_block_sse<big_endian, true>(out + n - 8, in + n - 8);
   71|    528|  } else {
   72|  1.03M|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (72:17): [True: 1.03M, False: 528]
  ------------------
   73|  1.03M|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
   74|  1.03M|    }
   75|       |
   76|    528|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
   77|    528|  }
   78|       |
   79|    528|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (79:16): [True: 51, False: 477]
  ------------------
   80|    528|                   ? replacement
   81|    528|                   : out[n - 1];
   82|    528|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDs:
   11|  1.03M|                                              const char16_t *in) {
   12|  1.03M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   13|  1.03M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   14|  1.03M|  };
   15|  1.03M|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   16|       |
   17|  1.03M|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   18|  1.03M|  __m128i illseq, lb_illseq, block_illseq;
   19|       |
   20|  1.03M|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   21|  1.03M|  block = _mm_loadu_si128((const __m128i *)in);
   22|  1.03M|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   23|  1.03M|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   24|  1.03M|  lb_is_high =
   25|  1.03M|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   26|  1.03M|  block_is_low =
   27|  1.03M|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   28|       |
   29|  1.03M|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   30|  1.03M|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (30:7): [True: 69.8k, False: 963k]
  ------------------
   31|  69.8k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  69.8k|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   35|  69.8k|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   36|  69.8k|                                _mm_bsrli_si128(lb_illseq, 2));
   37|       |
   38|       |    /* fix illegal sequencing in the lookback */
   39|  69.8k|    lb = _mm_cvtsi128_si32(lb_illseq);
   40|  69.8k|    lb = (lb & replacement) | (~lb & out[-1]);
   41|  69.8k|    out[-1] = char16_t(lb);
   42|       |    /* fix illegal sequencing in the main block */
   43|  69.8k|    block =
   44|  69.8k|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
   45|  69.8k|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
   46|  69.8k|    _mm_storeu_si128((__m128i *)out, block);
   47|   963k|  } else if (!in_place) {
  ------------------
  |  Branch (47:14): [True: 963k, Folded]
  ------------------
   48|   963k|    _mm_storeu_si128((__m128i *)out, block);
   49|   963k|  }
   50|  1.03M|}
simdutf.cpp:_ZZN7simdutf8westmere12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDsENKUltE_clEt:
   12|  4.13M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   13|  4.13M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   14|  4.13M|  };

simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_123utf16_gather_high_bytesILNS_10endiannessE0EEENS1_4simd5simd8IhEENS4_6simd16ItEES8_:
    3|   759k|                                       const simd16<uint16_t> in1) {
    4|   759k|  if (big_endian) {
  ------------------
  |  Branch (4:7): [Folded, False: 759k]
  ------------------
    5|       |    // we want lower bytes
    6|      0|    const auto mask = simd16<uint16_t>(0x00ff);
    7|      0|    const auto t0 = in0 & mask;
    8|      0|    const auto t1 = in1 & mask;
    9|       |
   10|      0|    return simd16<uint16_t>::pack(t0, t1);
   11|   759k|  } else {
   12|   759k|    const auto t0 = in0.shr<8>();
   13|   759k|    const auto t1 = in1.shr<8>();
   14|       |
   15|   759k|    return simd16<uint16_t>::pack(t0, t1);
   16|   759k|  }
   17|   759k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_123utf16_gather_high_bytesILNS_10endiannessE1EEENS1_4simd5simd8IhEENS4_6simd16ItEES8_:
    3|   516k|                                       const simd16<uint16_t> in1) {
    4|   516k|  if (big_endian) {
  ------------------
  |  Branch (4:7): [True: 516k, Folded]
  ------------------
    5|       |    // we want lower bytes
    6|   516k|    const auto mask = simd16<uint16_t>(0x00ff);
    7|   516k|    const auto t0 = in0 & mask;
    8|   516k|    const auto t1 = in1 & mask;
    9|       |
   10|   516k|    return simd16<uint16_t>::pack(t0, t1);
   11|   516k|  } else {
   12|      0|    const auto t0 = in0.shr<8>();
   13|      0|    const auto t1 = in1.shr<8>();
   14|       |
   15|      0|    return simd16<uint16_t>::pack(t0, t1);
   16|      0|  }
   17|   516k|}

