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

_Z10autodetectNSt3__14spanIKcLm18446744073709551615EEE:
    9|    670|void autodetect(std::span<const char> chardata) {
   10|    670|  std::vector<simdutf::encoding_type> results;
   11|    670|  const auto implementations = get_supported_implementations();
   12|  2.01k|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (12:44): [True: 2.01k, False: 670]
  ------------------
   13|  2.01k|    results.push_back(
   14|  2.01k|        impl->autodetect_encoding(chardata.data(), chardata.size()));
   15|  2.01k|  }
   16|    670|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   17|    670|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (17:7): [True: 0, False: 670]
  ------------------
   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|    670|}
_Z6detectNSt3__14spanIKcLm18446744073709551615EEE:
   27|    652|void detect(std::span<const char> chardata) {
   28|    652|  std::vector<int> results;
   29|    652|  const auto implementations = get_supported_implementations();
   30|  1.95k|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (30:44): [True: 1.95k, False: 652]
  ------------------
   31|  1.95k|    results.push_back(impl->detect_encodings(chardata.data(), chardata.size()));
   32|  1.95k|  }
   33|    652|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   34|    652|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (34:7): [True: 0, False: 652]
  ------------------
   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|    652|}
_Z14validate_asciiNSt3__14spanIKcLm18446744073709551615EEE:
   50|    212|void validate_ascii(std::span<const char> chardata) {
   51|       |  // use int, not bool to avoid vector<bool>
   52|    212|  std::vector<int> results;
   53|    212|  const auto implementations = get_supported_implementations();
   54|    636|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (54:44): [True: 636, False: 212]
  ------------------
   55|    636|    results.push_back(+impl->validate_ascii(chardata.data(), chardata.size()));
   56|    636|  }
   57|    212|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   58|    212|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (58:7): [True: 0, False: 212]
  ------------------
   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|    212|}
_Z23validate_ascii_with_errNSt3__14spanIKcLm18446744073709551615EEE:
   74|    256|void validate_ascii_with_err(std::span<const char> chardata) {
   75|       |  // use int, not bool to avoid vector<bool>
   76|    256|  std::vector<simdutf::result> results;
   77|    256|  const auto implementations = get_supported_implementations();
   78|    768|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (78:44): [True: 768, False: 256]
  ------------------
   79|    768|    results.push_back(
   80|    768|        impl->validate_ascii_with_errors(chardata.data(), chardata.size()));
   81|    768|  }
   82|    256|  auto neq = [](const auto& a, const auto& b) { return a != b; };
   83|    256|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (83:7): [True: 0, False: 256]
  ------------------
   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|    256|}
_Z16utf16_endiannessNSt3__14spanIKDsLm18446744073709551615EEE:
   99|    130|void utf16_endianness(std::span<const char16_t> data) {
  100|    130|  std::vector<std::string> results;
  101|    130|  const auto implementations = get_supported_implementations();
  102|    390|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (102:44): [True: 390, False: 130]
  ------------------
  103|    390|    std::vector<char16_t> out(data.size());
  104|    390|    impl->change_endianness_utf16(data.data(), data.size(), out.data());
  105|    390|    results.push_back(FNV1A_hash::as_str(out));
  106|    390|  }
  107|    130|  auto neq = [](const auto& a, const auto& b) { return a != b; };
  108|    130|  if (std::ranges::adjacent_find(results, neq) != results.end()) {
  ------------------
  |  Branch (108:7): [True: 0, False: 130]
  ------------------
  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|    130|}
_Z23validate_utf16_as_asciiNSt3__14spanIKDsLm18446744073709551615EEE:
  126|    226|void validate_utf16_as_ascii(std::span<const char16_t> data) {
  127|    226|  const auto implementations = get_supported_implementations();
  128|       |  // use int, not bool to avoid vector<bool>
  129|    226|  std::vector<int> le_results, be_results;
  130|    226|  le_results.reserve(implementations.size());
  131|    226|  be_results.reserve(implementations.size());
  132|    678|  for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (132:44): [True: 678, False: 226]
  ------------------
  133|    678|    le_results.push_back(
  134|    678|        +impl->validate_utf16le_as_ascii(data.data(), data.size()));
  135|    678|    be_results.push_back(
  136|    678|        +impl->validate_utf16be_as_ascii(data.data(), data.size()));
  137|    678|  }
  138|    226|  auto neq = [](const auto& a, const auto& b) { return a != b; };
  139|    226|  if (std::ranges::adjacent_find(le_results, neq) != le_results.end()) {
  ------------------
  |  Branch (139:7): [True: 0, False: 226]
  ------------------
  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|    226|  if (std::ranges::adjacent_find(be_results, neq) != be_results.end()) {
  ------------------
  |  Branch (148:7): [True: 0, False: 226]
  ------------------
  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|    226|  if (le_results[0]) {
  ------------------
  |  Branch (159:7): [True: 28, False: 198]
  ------------------
  160|     84|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (160:46): [True: 84, False: 28]
  ------------------
  161|     84|      if (!impl->validate_utf16le(data.data(), data.size())) {
  ------------------
  |  Branch (161:11): [True: 0, False: 84]
  ------------------
  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|     84|    }
  168|     28|  }
  169|       |  // Same for BE.
  170|    226|  if (be_results[0]) {
  ------------------
  |  Branch (170:7): [True: 26, False: 200]
  ------------------
  171|     78|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (171:46): [True: 78, False: 26]
  ------------------
  172|     78|      if (!impl->validate_utf16be(data.data(), data.size())) {
  ------------------
  |  Branch (172:11): [True: 0, False: 78]
  ------------------
  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|     78|    }
  179|     26|  }
  180|    226|}
_Z20to_well_formed_utf16NSt3__14spanIKDsLm18446744073709551615EEE:
  186|    631|void to_well_formed_utf16(std::span<const char16_t> data) {
  187|    631|  const auto implementations = get_supported_implementations();
  188|    631|  if (implementations.empty()) {
  ------------------
  |  Branch (188:7): [True: 0, False: 631]
  ------------------
  189|      0|    return;
  190|      0|  }
  191|       |
  192|       |  // Check LE variant
  193|    631|  {
  194|    631|    std::vector<std::vector<char16_t>> le_outputs;
  195|    631|    le_outputs.reserve(implementations.size());
  196|  1.89k|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (196:46): [True: 1.89k, False: 631]
  ------------------
  197|  1.89k|      std::vector<char16_t> out(data.size());
  198|  1.89k|      impl->to_well_formed_utf16le(data.data(), data.size(), out.data());
  199|  1.89k|      le_outputs.push_back(std::move(out));
  200|  1.89k|    }
  201|    631|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  202|    631|    if (std::ranges::adjacent_find(le_outputs, neq) != le_outputs.end()) {
  ------------------
  |  Branch (202:9): [True: 0, False: 631]
  ------------------
  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.52k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (212:29): [True: 1.89k, False: 631]
  ------------------
  213|  1.89k|      if (!implementations[i]->validate_utf16le(le_outputs[i].data(),
  ------------------
  |  Branch (213:11): [True: 0, False: 1.89k]
  ------------------
  214|  1.89k|                                                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|  1.89k|    }
  220|       |    // If input was already valid UTF-16LE, output must equal input.
  221|    631|    if (implementations[0]->validate_utf16le(data.data(), data.size())) {
  ------------------
  |  Branch (221:9): [True: 196, False: 435]
  ------------------
  222|    196|      if (!std::ranges::equal(le_outputs[0], data)) {
  ------------------
  |  Branch (222:11): [True: 0, False: 196]
  ------------------
  223|      0|        std::cerr << "to_well_formed_utf16le: valid input was modified\n";
  224|      0|        std::abort();
  225|      0|      }
  226|    196|    }
  227|    631|  }
  228|       |
  229|       |  // Check BE variant
  230|    631|  {
  231|    631|    std::vector<std::vector<char16_t>> be_outputs;
  232|    631|    be_outputs.reserve(implementations.size());
  233|  1.89k|    for (const simdutf::implementation* impl : implementations) {
  ------------------
  |  Branch (233:46): [True: 1.89k, False: 631]
  ------------------
  234|  1.89k|      std::vector<char16_t> out(data.size());
  235|  1.89k|      impl->to_well_formed_utf16be(data.data(), data.size(), out.data());
  236|  1.89k|      be_outputs.push_back(std::move(out));
  237|  1.89k|    }
  238|    631|    auto neq = [](const auto& a, const auto& b) { return a != b; };
  239|    631|    if (std::ranges::adjacent_find(be_outputs, neq) != be_outputs.end()) {
  ------------------
  |  Branch (239:9): [True: 0, False: 631]
  ------------------
  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.52k|    for (std::size_t i = 0; i < implementations.size(); ++i) {
  ------------------
  |  Branch (249:29): [True: 1.89k, False: 631]
  ------------------
  250|  1.89k|      if (!implementations[i]->validate_utf16be(be_outputs[i].data(),
  ------------------
  |  Branch (250:11): [True: 0, False: 1.89k]
  ------------------
  251|  1.89k|                                                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|  1.89k|    }
  257|       |    // If input was already valid UTF-16BE, output must equal input.
  258|    631|    if (implementations[0]->validate_utf16be(data.data(), data.size())) {
  ------------------
  |  Branch (258:9): [True: 207, False: 424]
  ------------------
  259|    207|      if (!std::ranges::equal(be_outputs[0], data)) {
  ------------------
  |  Branch (259:11): [True: 0, False: 207]
  ------------------
  260|      0|        std::cerr << "to_well_formed_utf16be: valid input was modified\n";
  261|      0|        std::abort();
  262|      0|      }
  263|    207|    }
  264|    631|  }
  265|    631|}
_Z27convert_latin1_to_utf8_safeNSt3__14spanIKcLm18446744073709551615EEEm:
  268|    261|                                 const std::size_t outputsize) {
  269|       |  // convert with a limited output buffer
  270|    261|  std::vector<char> limited_output(outputsize);
  271|    261|  const auto limited_ret = simdutf::convert_latin1_to_utf8_safe(
  272|    261|      chardata.data(), chardata.size(), limited_output.data(), outputsize);
  273|       |
  274|       |  // convert with a sufficiently large output buffer
  275|    261|  std::vector<char> large_output(2 * chardata.size());
  276|    261|  const auto large_ret = simdutf::convert_latin1_to_utf8(
  277|    261|      chardata.data(), chardata.size(), large_output.data());
  278|       |
  279|    261|  if (large_ret != 0) {
  ------------------
  |  Branch (279:7): [True: 234, False: 27]
  ------------------
  280|       |    // conversion was possible with a large buffer.
  281|    234|    if (large_ret <= outputsize) {
  ------------------
  |  Branch (281:9): [True: 109, False: 125]
  ------------------
  282|       |      // the limited buffer was large enough, ensure we got the same result
  283|    109|      assert(limited_ret == large_ret);
  ------------------
  |  Branch (283:7): [True: 109, False: 0]
  ------------------
  284|    109|      assert(std::ranges::equal(limited_output | std::views::take(large_ret),
  ------------------
  |  Branch (284:7): [True: 109, False: 0]
  ------------------
  285|    109|                                large_output | std::views::take(large_ret)));
  286|    125|    } else {
  287|       |      // the number of written bytes for a limited buffer must not exceed what
  288|       |      // the large buffer got.
  289|    125|      assert(limited_ret <= large_ret);
  ------------------
  |  Branch (289:7): [True: 125, False: 0]
  ------------------
  290|       |      // the written data should be equal
  291|    125|      assert(std::ranges::equal(limited_output | std::views::take(limited_ret),
  ------------------
  |  Branch (291:7): [True: 125, False: 0]
  ------------------
  292|    125|                                large_output | std::views::take(limited_ret)));
  293|    125|    }
  294|    234|  } 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|     27|  }
  298|    261|}
LLVMFuzzerTestOneInput:
  300|  3.23k|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.23k|  if (size < 4) {
  ------------------
  |  Branch (304:7): [True: 2, False: 3.23k]
  ------------------
  305|      2|    return 0;
  306|      2|  }
  307|  3.23k|  constexpr auto Ncases = 11u;
  308|  3.23k|  constexpr auto actionmask = std::bit_ceil(Ncases) - 1;
  309|  3.23k|  const auto action = data[0] & actionmask;
  310|       |
  311|  3.23k|  const std::uint16_t u16 = data[1] + (data[2] << 8);
  312|       |
  313|  3.23k|  data += 4;
  314|  3.23k|  size -= 4;
  315|       |
  316|  3.23k|  const std::span<const char> chardata{(const char*)data, size};
  317|  3.23k|  const std::span<const char16_t> u16data{(const char16_t*)data,
  318|  3.23k|                                          size / sizeof(char16_t)};
  319|       |
  320|  3.23k|  switch (action) {
  ------------------
  |  Branch (320:11): [True: 3.23k, False: 1]
  ------------------
  321|    670|  case 0:
  ------------------
  |  Branch (321:3): [True: 670, False: 2.56k]
  ------------------
  322|    670|    autodetect(chardata);
  323|    670|    break;
  324|    652|  case 1:
  ------------------
  |  Branch (324:3): [True: 652, False: 2.58k]
  ------------------
  325|    652|    detect(chardata);
  326|    652|    break;
  327|    212|  case 2:
  ------------------
  |  Branch (327:3): [True: 212, False: 3.02k]
  ------------------
  328|    212|    validate_ascii(chardata);
  329|    212|    break;
  330|    256|  case 3:
  ------------------
  |  Branch (330:3): [True: 256, False: 2.97k]
  ------------------
  331|    256|    validate_ascii_with_err(chardata);
  332|    256|    break;
  333|    130|  case 4:
  ------------------
  |  Branch (333:3): [True: 130, False: 3.10k]
  ------------------
  334|    130|    utf16_endianness(u16data);
  335|    130|    break;
  336|     42|  case 5: {
  ------------------
  |  Branch (336:3): [True: 42, False: 3.19k]
  ------------------
  337|     42|    [[maybe_unused]] auto ret =
  338|     42|        simdutf::trim_partial_utf16le(u16data.data(), u16data.size());
  339|     42|    assert(ret == u16data.size() || ret + 1 == u16data.size());
  ------------------
  |  Branch (339:5): [True: 21, False: 21]
  |  Branch (339:5): [True: 21, False: 0]
  |  Branch (339:5): [True: 42, False: 0]
  ------------------
  340|     42|  } break;
  341|     47|  case 6: {
  ------------------
  |  Branch (341:3): [True: 47, False: 3.18k]
  ------------------
  342|     47|    [[maybe_unused]] auto ret =
  343|     47|        simdutf::trim_partial_utf16be(u16data.data(), u16data.size());
  344|     47|    assert(ret == u16data.size() || ret + 1 == u16data.size());
  ------------------
  |  Branch (344:5): [True: 27, False: 20]
  |  Branch (344:5): [True: 20, False: 0]
  |  Branch (344:5): [True: 47, False: 0]
  ------------------
  345|     47|  } break;
  346|    104|  case 7: {
  ------------------
  |  Branch (346:3): [True: 104, False: 3.12k]
  ------------------
  347|    104|    [[maybe_unused]] const std::size_t N = chardata.size();
  348|    104|    [[maybe_unused]] const auto ret =
  349|    104|        simdutf::trim_partial_utf8(chardata.data(), chardata.size());
  350|    104|    if ((ret + 3 < N) || (ret > N)) {
  ------------------
  |  Branch (350:9): [True: 0, False: 104]
  |  Branch (350:26): [True: 0, False: 104]
  ------------------
  351|      0|      std::cerr << "ret=" << ret << " N=" << N << '\n';
  352|      0|      std::abort();
  353|      0|    }
  354|    104|  } break;
  355|    261|  case 8:
  ------------------
  |  Branch (355:3): [True: 261, False: 2.97k]
  ------------------
  356|    261|    convert_latin1_to_utf8_safe(chardata, u16);
  357|    261|    break;
  358|    226|  case 9:
  ------------------
  |  Branch (358:3): [True: 226, False: 3.00k]
  ------------------
  359|    226|    validate_utf16_as_ascii(u16data);
  360|    226|    break;
  361|    631|  case 10:
  ------------------
  |  Branch (361:3): [True: 631, False: 2.60k]
  ------------------
  362|    631|    to_well_formed_utf16(u16data);
  363|    631|    break;
  364|  3.23k|  }
  365|  3.23k|  return 0;
  366|  3.23k|}
misc.cpp:_ZZ10autodetectNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIN7simdutf13encoding_typeES6_EEDaRKT_RKT0_:
   16|  1.34k|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ6detectNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
   33|  1.30k|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ14validate_asciiNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
   57|    424|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ23validate_ascii_with_errNSt3__14spanIKcLm18446744073709551615EEEENK3$_0clIN7simdutf6resultES6_EEDaRKT_RKT0_:
   82|    512|  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|    260|  auto neq = [](const auto& a, const auto& b) { return a != b; };
misc.cpp:_ZZ23validate_utf16_as_asciiNSt3__14spanIKDsLm18446744073709551615EEEENK3$_0clIiiEEDaRKT_RKT0_:
  138|    904|  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.26k|    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.26k|    auto neq = [](const auto& a, const auto& b) { return a != b; };

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

_ZNK7simdutf14implementation4nameEv:
 5121|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5172|     10|  virtual uint32_t required_instruction_sets() const {
 5173|     10|    return _required_instruction_sets;
 5174|     10|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7058|      5|      : _name(name), _description(description),
 7059|      5|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7090|      1|  simdutf_really_inline available_implementation_list() {}
simdutf.cpp:_ZN7simdutf6detail12_GLOBAL__N_13minEmm:
   59|    544|constexpr std::size_t min(std::size_t a, std::size_t b) {
   60|    544|  return a < b ? a : b;
  ------------------
  |  Branch (60:10): [True: 149, False: 395]
  ------------------
   61|    544|}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEaSEPS3_:
 7161|      1|  atomic_ptr &operator=(T *_ptr) {
 7162|      1|    ptr = _ptr;
 7163|      1|    return *this;
 7164|      1|  }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEcvPS3_Ev:
 7158|      1|  operator T *() { return ptr.load(); }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEC2EPS3_:
 7138|      1|  atomic_ptr(T *_ptr) : ptr{_ptr} {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEptEv:
 7160|    544|  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|    212|                                                      size_t len) noexcept {
   17|    212|  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|    212|  {
   25|   124k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (25:12): [True: 124k, False: 81]
  ------------------
   26|   124k|      uint64_t v1;
   27|   124k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   28|   124k|      uint64_t v2;
   29|   124k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   30|   124k|      uint64_t v{v1 | v2};
   31|   124k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (31:11): [True: 131, False: 123k]
  ------------------
   32|    131|        return false;
   33|    131|      }
   34|   124k|    }
   35|    212|  }
   36|       |
   37|       |  // process the tail byte-by-byte
   38|    453|  for (; pos < len; pos++) {
  ------------------
  |  Branch (38:10): [True: 409, False: 44]
  ------------------
   39|    409|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (39:9): [True: 37, False: 372]
  ------------------
   40|     37|      return false;
   41|     37|    }
   42|    409|  }
   43|     44|  return true;
   44|     81|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_15ascii20validate_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_m:
   50|    706|validate_with_errors(InputPtr data, size_t len) noexcept {
   51|    706|  size_t pos = 0;
   52|       |#if SIMDUTF_CPLUSPLUS23
   53|       |  // avoid memcpy during constant evaluation
   54|       |  if !consteval
   55|       |#endif
   56|    706|  {
   57|       |    // process in blocks of 16 bytes when possible
   58|   169k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (58:12): [True: 169k, False: 169]
  ------------------
   59|   169k|      uint64_t v1;
   60|   169k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   61|   169k|      uint64_t v2;
   62|   169k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   63|   169k|      uint64_t v{v1 | v2};
   64|   169k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (64:11): [True: 537, False: 169k]
  ------------------
   65|  3.09k|        for (; pos < len; pos++) {
  ------------------
  |  Branch (65:16): [True: 3.09k, False: 0]
  ------------------
   66|  3.09k|          if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (66:15): [True: 537, False: 2.55k]
  ------------------
   67|    537|            return result(error_code::TOO_LARGE, pos);
   68|    537|          }
   69|  3.09k|        }
   70|    537|      }
   71|   169k|    }
   72|    706|  }
   73|       |
   74|       |  // process the tail byte-by-byte
   75|    571|  for (; pos < len; pos++) {
  ------------------
  |  Branch (75:10): [True: 540, False: 31]
  ------------------
   76|    540|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (76:9): [True: 138, False: 402]
  ------------------
   77|    138|      return result(error_code::TOO_LARGE, pos);
   78|    138|    }
   79|    540|  }
   80|     31|  return result(error_code::SUCCESS, pos);
   81|    169|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf812convert_safeEPKcmPcm:
   72|    261|                           size_t utf8_len) {
   73|    261|  const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   74|    261|  size_t pos = 0;
   75|    261|  size_t skip_pos = 0;
   76|    261|  size_t utf8_pos = 0;
   77|  1.40k|  while (pos < len && utf8_pos < utf8_len) {
  ------------------
  |  Branch (77:10): [True: 1.27k, False: 136]
  |  Branch (77:23): [True: 1.17k, False: 95]
  ------------------
   78|       |    // try to convert the next block of 16 ASCII bytes
   79|  1.17k|    if (pos >= skip_pos && pos + 16 <= len &&
  ------------------
  |  Branch (79:9): [True: 601, False: 576]
  |  Branch (79:28): [True: 316, False: 285]
  ------------------
   80|    316|        utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes,
  ------------------
  |  Branch (80:9): [True: 75, False: 241]
  ------------------
   81|       |                                     // check that they are ascii
   82|     75|      uint64_t v1;
   83|     75|      ::memcpy(&v1, data + pos, sizeof(uint64_t));
   84|     75|      uint64_t v2;
   85|     75|      ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   86|     75|      uint64_t v{v1 |
   87|     75|                 v2}; // We are only interested in these bits: 1000 1000 1000
   88|       |                      // 1000, so it makes sense to concatenate everything
   89|     75|      if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (89:11): [True: 37, False: 38]
  ------------------
   90|     75|          0) { // if NONE of these are set, e.g. all of them are zero, then
   91|       |               // everything is ASCII
   92|     37|        ::memcpy(utf8_output + utf8_pos, buf + pos, 16);
   93|     37|        utf8_pos += 16;
   94|     37|        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.10k|    } else {
  101|  1.10k|      const auto byte = data[pos];
  102|  1.10k|      if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (102:11): [True: 667, False: 435]
  ------------------
  103|       |        // will generate one UTF-8 bytes
  104|    667|        utf8_output[utf8_pos++] = char(byte);
  105|    667|        pos++;
  106|    667|      } else if (utf8_pos + 2 <= utf8_len) {
  ------------------
  |  Branch (106:18): [True: 405, False: 30]
  ------------------
  107|       |        // will generate two UTF-8 bytes
  108|    405|        utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
  109|    405|        utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
  110|    405|        pos++;
  111|    405|      } else {
  112|     30|        break;
  113|     30|      }
  114|  1.10k|    }
  115|  1.17k|  }
  116|    261|  return utf8_pos;
  117|    261|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertEPKcmPc:
   66|    517|                                     char *utf8_output) {
   67|    517|  return convert(reinterpret_cast<const unsigned char *>(buf), len,
   68|    517|                 utf8_output);
   69|    517|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_:
   17|    517|                                   OutputPtr utf8_output) {
   18|       |  // const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   19|    517|  size_t pos = 0;
   20|    517|  size_t utf8_pos = 0;
   21|       |
   22|  6.81k|  while (pos < len) {
  ------------------
  |  Branch (22:10): [True: 6.30k, False: 517]
  ------------------
   23|       |#if SIMDUTF_CPLUSPLUS23
   24|       |    if !consteval
   25|       |#endif
   26|  6.30k|    {
   27|       |      // try to convert the next block of 16 ASCII bytes
   28|  6.30k|      if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that
  ------------------
  |  Branch (28:11): [True: 1.07k, False: 5.23k]
  ------------------
   29|       |                             // they are ascii
   30|  1.07k|        uint64_t v1;
   31|  1.07k|        ::memcpy(&v1, data + pos, sizeof(uint64_t));
   32|  1.07k|        uint64_t v2;
   33|  1.07k|        ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   34|  1.07k|        uint64_t v{v1 |
   35|  1.07k|                   v2}; // We are only interested in these bits: 1000 1000 1000
   36|       |                        // 1000, so it makes sense to concatenate everything
   37|  1.07k|        if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (37:13): [True: 146, False: 925]
  ------------------
   38|  1.07k|            0) { // if NONE of these are set, e.g. all of them are zero, then
   39|       |                 // everything is ASCII
   40|    146|          size_t final_pos = pos + 16;
   41|  2.48k|          while (pos < final_pos) {
  ------------------
  |  Branch (41:18): [True: 2.33k, False: 146]
  ------------------
   42|  2.33k|            utf8_output[utf8_pos++] = char(data[pos]);
   43|  2.33k|            pos++;
   44|  2.33k|          }
   45|    146|          continue;
   46|    146|        }
   47|  1.07k|      } // if (pos + 16 <= len)
   48|  6.30k|    } // !consteval scope
   49|       |
   50|  6.15k|    unsigned char byte = data[pos];
   51|  6.15k|    if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (51:9): [True: 2.72k, False: 3.43k]
  ------------------
   52|       |      // will generate one UTF-8 bytes
   53|  2.72k|      utf8_output[utf8_pos++] = char(byte);
   54|  2.72k|      pos++;
   55|  3.43k|    } else {
   56|       |      // will generate two UTF-8 bytes
   57|  3.43k|      utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
   58|  3.43k|      utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
   59|  3.43k|      pos++;
   60|  3.43k|    }
   61|  6.15k|  } // while
   62|    517|  return utf8_pos;
   63|    517|}

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

_ZN7simdutf6scalar5utf1623change_endianness_utf16EPKDsmPDs:
  119|    390|change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) {
  120|  2.10M|  for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (120:22): [True: 2.10M, False: 390]
  ------------------
  121|  2.10M|    *output++ = char16_t(input[i] >> 8 | input[i] << 8);
  122|  2.10M|  }
  123|    390|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE1EEEmPKDsm:
  127|     47|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     47|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 46]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     46|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     46|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     46|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     46|  return length;
  135|     47|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE0EEEmPKDsm:
  127|     42|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     42|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 41]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     41|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     41|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     41|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     41|  return length;
  135|     42|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE0EEEbPKDsm:
   10|    226|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  12.6k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 12.6k, False: 28]
  ------------------
   12|  12.6k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  12.6k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 198, False: 12.4k]
  ------------------
   14|    198|      return false;
   15|    198|    }
   16|  12.6k|  }
   17|     28|  return true;
   18|    226|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE1EEEbPKDsm:
   10|    226|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  14.9k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 14.9k, False: 26]
  ------------------
   12|  14.9k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  14.9k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 200, False: 14.7k]
  ------------------
   14|    200|      return false;
   15|    200|    }
   16|  14.9k|  }
   17|     26|  return true;
   18|    226|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE0EEEbPKDsm:
   22|  3.76k|validate(const char16_t *data, size_t len) noexcept {
   23|  3.76k|  uint64_t pos = 0;
   24|  13.5M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 13.5M, False: 2.65k]
  ------------------
   25|  13.5M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  13.5M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 24.3k, False: 13.4M]
  ------------------
   27|  24.3k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 222, False: 24.1k]
  ------------------
   28|    222|        return false;
   29|    222|      }
   30|  24.1k|      char16_t diff = char16_t(word - 0xD800);
   31|  24.1k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 427, False: 23.7k]
  ------------------
   32|    427|        return false;
   33|    427|      }
   34|  23.7k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [Folded, False: 23.7k]
  ------------------
   35|  23.7k|                               ? u16_swap_bytes(data[pos + 1])
   36|  23.7k|                               : data[pos + 1];
   37|  23.7k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  23.7k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 462, False: 23.2k]
  ------------------
   39|    462|        return false;
   40|    462|      }
   41|  23.2k|      pos += 2;
   42|  13.4M|    } else {
   43|  13.4M|      pos++;
   44|  13.4M|    }
   45|  13.5M|  }
   46|  2.65k|  return true;
   47|  3.76k|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE1EEEbPKDsm:
   22|  2.41k|validate(const char16_t *data, size_t len) noexcept {
   23|  2.41k|  uint64_t pos = 0;
   24|  7.69M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 7.68M, False: 2.17k]
  ------------------
   25|  7.68M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  7.68M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 22.9k, False: 7.66M]
  ------------------
   27|  22.9k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 42, False: 22.9k]
  ------------------
   28|     42|        return false;
   29|     42|      }
   30|  22.9k|      char16_t diff = char16_t(word - 0xD800);
   31|  22.9k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 93, False: 22.8k]
  ------------------
   32|     93|        return false;
   33|     93|      }
   34|  22.8k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [True: 22.8k, Folded]
  ------------------
   35|  22.8k|                               ? u16_swap_bytes(data[pos + 1])
   36|  22.8k|                               : data[pos + 1];
   37|  22.8k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  22.8k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 107, False: 22.7k]
  ------------------
   39|    107|        return false;
   40|    107|      }
   41|  22.7k|      pos += 2;
   42|  7.66M|    } else {
   43|  7.66M|      pos++;
   44|  7.66M|    }
   45|  7.68M|  }
   46|  2.17k|  return true;
   47|  2.41k|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE0EEEvPKDsmPDs:
  190|    947|                                              char16_t *output) {
  191|    947|  const char16_t replacement = utf16::replacement<big_endian>();
  192|    947|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|    947|  size_t i = 0;
  194|  7.67M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 7.67M, False: 947]
  ------------------
  195|  7.67M|    char16_t c = input[i];
  196|  7.67M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  7.67M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  7.67M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 41.3k, False: 7.62M]
  |  Branch (198:32): [True: 20.1k, False: 21.1k]
  ------------------
  199|  20.1k|      output[i - 1] = replacement;
  200|  20.1k|    }
  201|       |
  202|  7.67M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 7.62M, False: 41.3k]
  |  Branch (202:33): [True: 210k, False: 7.41M]
  ------------------
  203|   210k|      output[i] = replacement;
  204|  7.46M|    } else {
  205|  7.46M|      output[i] = input[i];
  206|  7.46M|    }
  207|  7.67M|    high_surrogate_prev = high_surrogate;
  208|  7.67M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|    947|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 162, False: 785]
  ------------------
  212|    162|    output[i - 1] = replacement;
  213|    162|  }
  214|    947|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  7.67M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  7.67M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  7.67M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 505k, False: 7.16M]
  |  Branch (139:26): [True: 41.6k, False: 464k]
  ------------------
  140|  7.67M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  7.67M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  7.67M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  7.67M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 464k, False: 7.20M]
  |  Branch (144:26): [True: 231k, False: 232k]
  ------------------
  145|  7.67M|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE1EEEvPKDsmPDs:
  190|    947|                                              char16_t *output) {
  191|    947|  const char16_t replacement = utf16::replacement<big_endian>();
  192|    947|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|    947|  size_t i = 0;
  194|  7.67M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 7.67M, False: 947]
  ------------------
  195|  7.67M|    char16_t c = input[i];
  196|  7.67M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  7.67M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  7.67M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 41.7k, False: 7.62M]
  |  Branch (198:32): [True: 20.2k, False: 21.5k]
  ------------------
  199|  20.2k|      output[i - 1] = replacement;
  200|  20.2k|    }
  201|       |
  202|  7.67M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 7.62M, False: 41.7k]
  |  Branch (202:33): [True: 210k, False: 7.41M]
  ------------------
  203|   210k|      output[i] = replacement;
  204|  7.45M|    } else {
  205|  7.45M|      output[i] = input[i];
  206|  7.45M|    }
  207|  7.67M|    high_surrogate_prev = high_surrogate;
  208|  7.67M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|    947|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 102, False: 845]
  ------------------
  212|    102|    output[i - 1] = replacement;
  213|    102|  }
  214|    947|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  7.67M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  7.67M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  7.67M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 505k, False: 7.16M]
  |  Branch (139:26): [True: 41.9k, False: 463k]
  ------------------
  140|  7.67M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  7.67M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  7.67M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  7.67M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 463k, False: 7.20M]
  |  Branch (144:26): [True: 232k, False: 231k]
  ------------------
  145|  7.67M|}

_ZN7simdutf6scalar5utf328validateEPKDim:
   25|    804|                                                        size_t len) noexcept {
   26|    804|  return validate(reinterpret_cast<const uint32_t *>(buf), len);
   27|    804|}
_ZN7simdutf6scalar5utf328validateIPKjQsr7simdutf6detailE19indexes_into_uint32IT_EEEbS5_m:
   13|    804|                                                      size_t len) noexcept {
   14|    804|  uint64_t pos = 0;
   15|  21.5k|  for (; pos < len; pos++) {
  ------------------
  |  Branch (15:10): [True: 21.3k, False: 153]
  ------------------
   16|  21.3k|    uint32_t word = data[pos];
   17|  21.3k|    if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) {
  ------------------
  |  Branch (17:9): [True: 563, False: 20.7k]
  |  Branch (17:29): [True: 1.08k, False: 19.7k]
  |  Branch (17:47): [True: 88, False: 1.00k]
  ------------------
   18|    651|      return false;
   19|    651|    }
   20|  21.3k|  }
   21|    153|  return true;
   22|    804|}

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

_ZN7simdutf3BOM9check_bomEPKhm:
   24|  3.96k|encoding_type check_bom(const uint8_t *byte, size_t length) {
   25|  3.96k|  if (length >= 2 && byte[0] == 0xff and byte[1] == 0xfe) {
  ------------------
  |  Branch (25:7): [True: 3.90k, False: 57]
  |  Branch (25:22): [True: 477, False: 3.43k]
  |  Branch (25:42): [True: 216, False: 261]
  ------------------
   26|    216|    if (length >= 4 && byte[2] == 0x00 and byte[3] == 0x0) {
  ------------------
  |  Branch (26:9): [True: 204, False: 12]
  |  Branch (26:24): [True: 90, False: 114]
  |  Branch (26:44): [True: 18, False: 72]
  ------------------
   27|     18|      return encoding_type::UTF32_LE;
   28|    198|    } else {
   29|    198|      return encoding_type::UTF16_LE;
   30|    198|    }
   31|  3.75k|  } else if (length >= 2 && byte[0] == 0xfe and byte[1] == 0xff) {
  ------------------
  |  Branch (31:14): [True: 3.69k, False: 57]
  |  Branch (31:29): [True: 105, False: 3.58k]
  |  Branch (31:49): [True: 6, False: 99]
  ------------------
   32|      6|    return encoding_type::UTF16_BE;
   33|  3.74k|  } else if (length >= 4 && byte[0] == 0x00 and byte[1] == 0x00 and
  ------------------
  |  Branch (33:14): [True: 3.16k, False: 576]
  |  Branch (33:29): [True: 1.02k, False: 2.13k]
  |  Branch (33:49): [True: 633, False: 396]
  ------------------
   34|    633|             byte[2] == 0xfe and byte[3] == 0xff) {
  ------------------
  |  Branch (34:14): [True: 54, False: 579]
  |  Branch (34:34): [True: 6, False: 48]
  ------------------
   35|      6|    return encoding_type::UTF32_BE;
   36|  3.73k|  } else if (length >= 3 && byte[0] == 0xef and byte[1] == 0xbb and
  ------------------
  |  Branch (36:14): [True: 3.43k, False: 306]
  |  Branch (36:29): [True: 291, False: 3.14k]
  |  Branch (36:49): [True: 132, False: 159]
  ------------------
   37|    132|             byte[2] == 0xbf) {
  ------------------
  |  Branch (37:14): [True: 6, False: 126]
  ------------------
   38|      6|    return encoding_type::UTF8;
   39|      6|  }
   40|  3.73k|  return encoding_type::unspecified;
   41|  3.96k|}
_ZN7simdutf3BOM9check_bomEPKcm:
   43|  3.96k|encoding_type check_bom(const char *byte, size_t length) {
   44|  3.96k|  return check_bom(reinterpret_cast<const uint8_t *>(byte), length);
   45|  3.96k|}

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116ascii_validation22generic_validate_asciiEPKcm:
   32|    212|bool generic_validate_ascii(const char *input, size_t length) {
   33|    212|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
   34|  31.1k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (34:10): [True: 31.0k, False: 143]
  ------------------
   35|  31.0k|    simd::simd8x64<uint8_t> in(reader.full_block());
   36|  31.0k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (36:9): [True: 69, False: 30.9k]
  ------------------
   37|     69|      return false;
   38|     69|    }
   39|  30.9k|    reader.advance();
   40|  30.9k|  }
   41|    143|  uint8_t block[64]{};
   42|    143|  reader.get_remainder(block);
   43|    143|  simd::simd8x64<uint8_t> in(block);
   44|    143|  return in.is_ascii();
   45|    212|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_116ascii_validation34generic_validate_ascii_with_errorsEPKcm:
    6|    256|result generic_validate_ascii_with_errors(const char *input, size_t length) {
    7|    256|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
    8|    256|  size_t count{0};
    9|  42.3k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (9:10): [True: 42.2k, False: 154]
  ------------------
   10|  42.2k|    simd::simd8x64<uint8_t> in(reader.full_block());
   11|  42.2k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (11:9): [True: 102, False: 42.1k]
  ------------------
   12|    102|      result res = scalar::ascii::validate_with_errors(
   13|    102|          reinterpret_cast<const char *>(input + count), length - count);
   14|    102|      return result(res.error, count + res.count);
   15|    102|    }
   16|  42.1k|    reader.advance();
   17|       |
   18|  42.1k|    count += 64;
   19|  42.1k|  }
   20|    154|  uint8_t block[64]{};
   21|    154|  reader.get_remainder(block);
   22|    154|  simd::simd8x64<uint8_t> in(block);
   23|    154|  if (!in.is_ascii()) {
  ------------------
  |  Branch (23:7): [True: 123, False: 31]
  ------------------
   24|    123|    result res = scalar::ascii::validate_with_errors(
   25|    123|        reinterpret_cast<const char *>(input + count), length - count);
   26|    123|    return result(res.error, count + res.count);
   27|    123|  } else {
   28|     31|    return result(error_code::SUCCESS, length);
   29|     31|  }
   30|    154|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116ascii_validation22generic_validate_asciiEPKcm:
   32|    212|bool generic_validate_ascii(const char *input, size_t length) {
   33|    212|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
   34|  31.1k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (34:10): [True: 31.0k, False: 143]
  ------------------
   35|  31.0k|    simd::simd8x64<uint8_t> in(reader.full_block());
   36|  31.0k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (36:9): [True: 69, False: 30.9k]
  ------------------
   37|     69|      return false;
   38|     69|    }
   39|  30.9k|    reader.advance();
   40|  30.9k|  }
   41|    143|  uint8_t block[64]{};
   42|    143|  reader.get_remainder(block);
   43|    143|  simd::simd8x64<uint8_t> in(block);
   44|    143|  return in.is_ascii();
   45|    212|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_116ascii_validation34generic_validate_ascii_with_errorsEPKcm:
    6|    256|result generic_validate_ascii_with_errors(const char *input, size_t length) {
    7|    256|  buf_block_reader<64> reader(reinterpret_cast<const uint8_t *>(input), length);
    8|    256|  size_t count{0};
    9|  42.3k|  while (reader.has_full_block()) {
  ------------------
  |  Branch (9:10): [True: 42.2k, False: 154]
  ------------------
   10|  42.2k|    simd::simd8x64<uint8_t> in(reader.full_block());
   11|  42.2k|    if (!in.is_ascii()) {
  ------------------
  |  Branch (11:9): [True: 102, False: 42.1k]
  ------------------
   12|    102|      result res = scalar::ascii::validate_with_errors(
   13|    102|          reinterpret_cast<const char *>(input + count), length - count);
   14|    102|      return result(res.error, count + res.count);
   15|    102|    }
   16|  42.1k|    reader.advance();
   17|       |
   18|  42.1k|    count += 64;
   19|  42.1k|  }
   20|    154|  uint8_t block[64]{};
   21|    154|  reader.get_remainder(block);
   22|    154|  simd::simd8x64<uint8_t> in(block);
   23|    154|  if (!in.is_ascii()) {
  ------------------
  |  Branch (23:7): [True: 123, False: 31]
  ------------------
   24|    123|    result res = scalar::ascii::validate_with_errors(
   25|    123|        reinterpret_cast<const char *>(input + count), length - count);
   26|    123|    return result(res.error, count + res.count);
   27|    123|  } else {
   28|     31|    return result(error_code::SUCCESS, length);
   29|     31|  }
   30|    154|}

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

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

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

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    226|                                                 size_t size) {
  131|    226|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    226|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 224]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    224|  size_t pos = 0;
  135|    574|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 518, False: 56]
  ------------------
  136|    518|    simd16x32<uint16_t> input_vec(
  137|    518|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    518|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    518|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 168, False: 350]
  ------------------
  143|       |      // Found a match, return the first one
  144|    168|      int index = trailing_zeroes(~matches) / 2;
  145|    168|      return result(error_code::TOO_LARGE, pos + index);
  146|    168|    }
  147|    518|  }
  148|       |
  149|       |  // Scalar tail
  150|    169|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 143, False: 26]
  ------------------
  151|       |
  152|    143|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    143|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 113]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    113|    pos++;
  157|    113|  }
  158|     26|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    226|                                                 size_t size) {
  131|    226|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    226|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 224]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    224|  size_t pos = 0;
  135|    648|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 591, False: 57]
  ------------------
  136|    591|    simd16x32<uint16_t> input_vec(
  137|    591|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    591|    if constexpr (!match_system(big_endian)) {
  139|    591|      input_vec.swap_bytes();
  140|    591|    }
  141|    591|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    591|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 167, False: 424]
  ------------------
  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|    591|  }
  148|       |
  149|       |  // Scalar tail
  150|    155|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 131, False: 24]
  ------------------
  151|       |
  152|    131|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    131|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 33, False: 98]
  ------------------
  154|     33|      return result(error_code::TOO_LARGE, pos);
  155|     33|    }
  156|     98|    pos++;
  157|     98|  }
  158|     24|  return result(error_code::SUCCESS, size);
  159|     57|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.65k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.65k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.65k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.65k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.65k|  const char16_t *start = input;
   55|  1.65k|  const char16_t *end = input + size;
   56|       |
   57|  1.65k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.65k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.65k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.65k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   793k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 791k, False: 1.41k]
  ------------------
   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|   791k|    auto in0 = simd16<uint16_t>(input);
   67|   791k|    auto in1 =
   68|   791k|        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|   791k|    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|   791k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   791k|    const uint16_t surrogates_bitmask =
   77|   791k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   791k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 776k, False: 15.2k]
  ------------------
   79|   776k|      input += 16;
   80|   776k|    } 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.2k|      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.2k|      const auto vH = (in & v_fc) == v_dc;
   93|  15.2k|      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.2k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  15.2k|      const uint16_t a = static_cast<uint16_t>(
  100|  15.2k|          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.2k|      const uint16_t b = static_cast<uint16_t>(
  104|  15.2k|          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.2k|      const uint16_t c = static_cast<uint16_t>(
  107|  15.2k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  15.2k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 13.1k, False: 2.07k]
  ------------------
  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: 1.84k, False: 237]
  ------------------
  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|  1.84k|        input += 15;
  119|  1.84k|      } else {
  120|    237|        return result(error_code::SURROGATE, input - start);
  121|    237|      }
  122|  15.2k|    }
  123|   791k|  }
  124|       |
  125|  1.41k|  return result(error_code::SUCCESS, input - start);
  126|  1.65k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|  1.28k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.28k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.28k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.28k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.28k|  const char16_t *start = input;
   55|  1.28k|  const char16_t *end = input + size;
   56|       |
   57|  1.28k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.28k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.28k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.28k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   588k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 587k, False: 1.10k]
  ------------------
   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|   587k|    auto in0 = simd16<uint16_t>(input);
   67|   587k|    auto in1 =
   68|   587k|        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|   587k|    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|   587k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   587k|    const uint16_t surrogates_bitmask =
   77|   587k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   587k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 571k, False: 15.7k]
  ------------------
   79|   571k|      input += 16;
   80|   571k|    } 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.7k|      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.7k|      const auto vH = (in & v_fc) == v_dc;
   93|  15.7k|      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.7k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  15.7k|      const uint16_t a = static_cast<uint16_t>(
  100|  15.7k|          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.7k|      const uint16_t b = static_cast<uint16_t>(
  104|  15.7k|          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.7k|      const uint16_t c = static_cast<uint16_t>(
  107|  15.7k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  15.7k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 13.5k, False: 2.19k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  13.5k|        input += 16;
  113|  13.5k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.01k, False: 182]
  ------------------
  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.01k|        input += 15;
  119|  2.01k|      } else {
  120|    182|        return result(error_code::SURROGATE, input - start);
  121|    182|      }
  122|  15.7k|    }
  123|   587k|  }
  124|       |
  125|  1.10k|  return result(error_code::SUCCESS, input - start);
  126|  1.28k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    226|                                                 size_t size) {
  131|    226|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    226|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 224]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    224|  size_t pos = 0;
  135|    574|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 518, False: 56]
  ------------------
  136|    518|    simd16x32<uint16_t> input_vec(
  137|    518|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    518|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    518|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 168, False: 350]
  ------------------
  143|       |      // Found a match, return the first one
  144|    168|      int index = trailing_zeroes(~matches) / 2;
  145|    168|      return result(error_code::TOO_LARGE, pos + index);
  146|    168|    }
  147|    518|  }
  148|       |
  149|       |  // Scalar tail
  150|    169|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 143, False: 26]
  ------------------
  151|       |
  152|    143|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    143|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 113]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    113|    pos++;
  157|    113|  }
  158|     26|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    226|                                                 size_t size) {
  131|    226|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    226|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 2, False: 224]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    224|  size_t pos = 0;
  135|    648|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 591, False: 57]
  ------------------
  136|    591|    simd16x32<uint16_t> input_vec(
  137|    591|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    591|    if constexpr (!match_system(big_endian)) {
  139|    591|      input_vec.swap_bytes();
  140|    591|    }
  141|    591|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    591|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 167, False: 424]
  ------------------
  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|    591|  }
  148|       |
  149|       |  // Scalar tail
  150|    155|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 131, False: 24]
  ------------------
  151|       |
  152|    131|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    131|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 33, False: 98]
  ------------------
  154|     33|      return result(error_code::TOO_LARGE, pos);
  155|     33|    }
  156|     98|    pos++;
  157|     98|  }
  158|     24|  return result(error_code::SUCCESS, size);
  159|     57|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.02k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.02k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.02k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.02k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.02k|  const char16_t *start = input;
   55|  1.02k|  const char16_t *end = input + size;
   56|       |
   57|  1.02k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.02k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.02k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.02k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   694k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 693k, False: 935]
  ------------------
   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|   693k|    auto in0 = simd16<uint16_t>(input);
   67|   693k|    auto in1 =
   68|   693k|        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|   693k|    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|   693k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   693k|    const uint16_t surrogates_bitmask =
   77|   693k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   693k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 678k, False: 14.8k]
  ------------------
   79|   678k|      input += 16;
   80|   678k|    } 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|  14.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|  14.8k|      const auto vH = (in & v_fc) == v_dc;
   93|  14.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|  14.8k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  14.8k|      const uint16_t a = static_cast<uint16_t>(
  100|  14.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|  14.8k|      const uint16_t b = static_cast<uint16_t>(
  104|  14.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|  14.8k|      const uint16_t c = static_cast<uint16_t>(
  107|  14.8k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  14.8k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 13.0k, False: 1.83k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  13.0k|        input += 16;
  113|  13.0k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.75k, False: 88]
  ------------------
  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|  1.75k|        input += 15;
  119|  1.75k|      } else {
  120|     88|        return result(error_code::SURROGATE, input - start);
  121|     88|      }
  122|  14.8k|    }
  123|   693k|  }
  124|       |
  125|    935|  return result(error_code::SUCCESS, input - start);
  126|  1.02k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|    654|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|    654|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    654|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 654]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|    654|  const char16_t *start = input;
   55|    654|  const char16_t *end = input + size;
   56|       |
   57|    654|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|    654|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|    654|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|    654|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   480k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 479k, False: 654]
  ------------------
   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|   479k|    auto in0 = simd16<uint16_t>(input);
   67|   479k|    auto in1 =
   68|   479k|        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|   479k|    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|   479k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   479k|    const uint16_t surrogates_bitmask =
   77|   479k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   479k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 464k, False: 14.8k]
  ------------------
   79|   464k|      input += 16;
   80|   464k|    } 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|  14.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|  14.8k|      const auto vH = (in & v_fc) == v_dc;
   93|  14.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|  14.8k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  14.8k|      const uint16_t a = static_cast<uint16_t>(
  100|  14.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|  14.8k|      const uint16_t b = static_cast<uint16_t>(
  104|  14.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|  14.8k|      const uint16_t c = static_cast<uint16_t>(
  107|  14.8k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  14.8k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 13.0k, False: 1.84k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  13.0k|        input += 16;
  113|  13.0k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.84k, 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|  1.84k|        input += 15;
  119|  1.84k|      } else {
  120|      0|        return result(error_code::SURROGATE, input - start);
  121|      0|      }
  122|  14.8k|    }
  123|   479k|  }
  124|       |
  125|    654|  return result(error_code::SUCCESS, input - start);
  126|    654|}

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

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_avxILNS_10endiannessE0EEEvPKDsmPDs:
  143|    631|void utf16fix_avx(const char16_t *in, size_t n, char16_t *out) {
  144|    631|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  145|    631|  size_t i;
  146|       |
  147|    631|  if (n < 17) {
  ------------------
  |  Branch (147:7): [True: 287, False: 344]
  ------------------
  148|    287|    utf16fix_sse<big_endian>(in, n, out);
  149|    287|    return;
  150|    287|  }
  151|       |
  152|    344|  out[0] =
  153|    344|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (153:7): [True: 23, False: 321]
  ------------------
  154|       |
  155|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  156|    344|  if (in == out) {
  ------------------
  |  Branch (156:7): [True: 0, False: 344]
  ------------------
  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|    344|  } else {
  163|   479k|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (163:17): [True: 478k, False: 344]
  ------------------
  164|   478k|      utf16fix_block<big_endian, false>(out + i, in + i);
  165|   478k|    }
  166|       |
  167|    344|    utf16fix_block<big_endian, false>(out + n - 16, in + n - 16);
  168|    344|  }
  169|       |
  170|    344|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (170:16): [True: 42, False: 302]
  ------------------
  171|    344|                   ? replacement
  172|    344|                   : out[n - 1];
  173|    344|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE0EEEvPKDsmPDs:
  110|    287|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
  111|    287|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  112|    287|  size_t i;
  113|       |
  114|    287|  if (n < 9) {
  ------------------
  |  Branch (114:7): [True: 158, False: 129]
  ------------------
  115|    158|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
  116|    158|    return;
  117|    158|  }
  118|       |
  119|    129|  out[0] =
  120|    129|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (120:7): [True: 23, False: 106]
  ------------------
  121|       |
  122|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  123|    129|  if (in == out) {
  ------------------
  |  Branch (123:7): [True: 0, False: 129]
  ------------------
  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|    129|  } else {
  130|    152|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (130:17): [True: 23, False: 129]
  ------------------
  131|     23|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
  132|     23|    }
  133|       |
  134|    129|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
  135|    129|  }
  136|       |
  137|    129|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (137:16): [True: 24, False: 105]
  ------------------
  138|    129|                   ? replacement
  139|    129|                   : out[n - 1];
  140|    129|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDs:
   72|    152|void utf16fix_block_sse(char16_t *out, const char16_t *in) {
   73|    152|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    152|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    152|  };
   76|    152|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   77|    152|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   78|    152|  __m128i illseq, lb_illseq, block_illseq;
   79|       |
   80|    152|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   81|    152|  block = _mm_loadu_si128((const __m128i *)in);
   82|    152|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   83|    152|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   84|    152|  lb_is_high =
   85|    152|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   86|    152|  block_is_low =
   87|    152|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   88|       |
   89|    152|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   90|    152|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (90:7): [True: 84, False: 68]
  ------------------
   91|       |    /* compute the cause of the illegal sequencing */
   92|     84|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   93|     84|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   94|     84|                                _mm_bsrli_si128(lb_illseq, 2));
   95|       |    /* fix illegal sequencing in the lookback */
   96|     84|    int lb = _mm_cvtsi128_si32(lb_illseq);
   97|     84|    lb = (lb & replacement) | (~lb & out[-1]);
   98|     84|    out[-1] = char16_t(lb);
   99|       |    /* fix illegal sequencing in the main block */
  100|     84|    block =
  101|     84|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
  102|     84|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
  103|     84|    _mm_storeu_si128((__m128i *)out, block);
  104|     84|  } else if (!in_place) {
  ------------------
  |  Branch (104:14): [True: 68, Folded]
  ------------------
  105|     68|    _mm_storeu_si128((__m128i *)out, block);
  106|     68|  }
  107|    152|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE0ELb0EEEvPDsPKDsENKUltE_clEt:
   73|    608|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    608|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    608|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE0ELb0EEEvPDsPKDs:
   10|   479k|void utf16fix_block(char16_t *out, const char16_t *in) {
   11|   479k|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|   479k|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|   479k|  };
   14|   479k|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   15|   479k|  __m256i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   16|   479k|  __m256i illseq, lb_illseq, block_illseq, lb_illseq_shifted;
   17|       |
   18|   479k|  lookback = _mm256_loadu_si256((const __m256i *)(in - 1));
   19|   479k|  block = _mm256_loadu_si256((const __m256i *)in);
   20|   479k|  lb_masked =
   21|   479k|      _mm256_and_si256(lookback, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   22|   479k|  block_masked =
   23|   479k|      _mm256_and_si256(block, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   24|   479k|  lb_is_high =
   25|   479k|      _mm256_cmpeq_epi16(lb_masked, _mm256_set1_epi16(swap_if_needed(0xd800u)));
   26|   479k|  block_is_low = _mm256_cmpeq_epi16(block_masked,
   27|   479k|                                    _mm256_set1_epi16(swap_if_needed(0xdc00u)));
   28|       |
   29|   479k|  illseq = _mm256_xor_si256(lb_is_high, block_is_low);
   30|   479k|  if (!_mm256_testz_si256(illseq, illseq)) {
  ------------------
  |  Branch (30:7): [True: 38.4k, False: 440k]
  ------------------
   31|  38.4k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  38.4k|    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|  38.4k|    lb_illseq_shifted =
   45|  38.4k|        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2),
   46|  38.4k|                        _mm256_zextsi128_si256(_mm_bslli_si128(
   47|  38.4k|                            _mm256_extracti128_si256(lb_illseq, 1), 14)));
   48|  38.4k|#endif // SIMDUTF_GCC9OROLDER
   49|  38.4k|    block_illseq = _mm256_or_si256(
   50|  38.4k|        _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|  38.4k|    lb = _mm256_cvtsi256_si32(lb_illseq);
   58|  38.4k|#endif
   59|  38.4k|    lb = (lb & replacement) | (~lb & out[-1]);
   60|  38.4k|    out[-1] = char16_t(lb);
   61|       |
   62|       |    /* fix illegal sequencing in the main block */
   63|  38.4k|    block =
   64|  38.4k|        _mm256_blendv_epi8(block, _mm256_set1_epi16(replacement), block_illseq);
   65|  38.4k|    _mm256_storeu_si256((__m256i *)out, block);
   66|   440k|  } else if (!in_place) {
  ------------------
  |  Branch (66:14): [True: 440k, Folded]
  ------------------
   67|   440k|    _mm256_storeu_si256((__m256i *)out, block);
   68|   440k|  }
   69|   479k|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE0ELb0EEEvPDsPKDsENKUltE_clEt:
   11|  1.91M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|  1.91M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|  1.91M|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_avxILNS_10endiannessE1EEEvPKDsmPDs:
  143|    631|void utf16fix_avx(const char16_t *in, size_t n, char16_t *out) {
  144|    631|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  145|    631|  size_t i;
  146|       |
  147|    631|  if (n < 17) {
  ------------------
  |  Branch (147:7): [True: 287, False: 344]
  ------------------
  148|    287|    utf16fix_sse<big_endian>(in, n, out);
  149|    287|    return;
  150|    287|  }
  151|       |
  152|    344|  out[0] =
  153|    344|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (153:7): [True: 28, False: 316]
  ------------------
  154|       |
  155|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  156|    344|  if (in == out) {
  ------------------
  |  Branch (156:7): [True: 0, False: 344]
  ------------------
  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|    344|  } else {
  163|   479k|    for (i = 1; i + 16 < n; i += 16) {
  ------------------
  |  Branch (163:17): [True: 478k, False: 344]
  ------------------
  164|   478k|      utf16fix_block<big_endian, false>(out + i, in + i);
  165|   478k|    }
  166|       |
  167|    344|    utf16fix_block<big_endian, false>(out + n - 16, in + n - 16);
  168|    344|  }
  169|       |
  170|    344|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (170:16): [True: 22, False: 322]
  ------------------
  171|    344|                   ? replacement
  172|    344|                   : out[n - 1];
  173|    344|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_112utf16fix_sseILNS_10endiannessE1EEEvPKDsmPDs:
  110|    287|void utf16fix_sse(const char16_t *in, size_t n, char16_t *out) {
  111|    287|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
  112|    287|  size_t i;
  113|       |
  114|    287|  if (n < 9) {
  ------------------
  |  Branch (114:7): [True: 158, False: 129]
  ------------------
  115|    158|    scalar::utf16::to_well_formed_utf16<big_endian>(in, n, out);
  116|    158|    return;
  117|    158|  }
  118|       |
  119|    129|  out[0] =
  120|    129|      scalar::utf16::is_low_surrogate<big_endian>(in[0]) ? replacement : in[0];
  ------------------
  |  Branch (120:7): [True: 18, False: 111]
  ------------------
  121|       |
  122|       |  /* duplicate code to have the compiler specialise utf16fix_block() */
  123|    129|  if (in == out) {
  ------------------
  |  Branch (123:7): [True: 0, False: 129]
  ------------------
  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|    129|  } else {
  130|    152|    for (i = 1; i + 8 < n; i += 8) {
  ------------------
  |  Branch (130:17): [True: 23, False: 129]
  ------------------
  131|     23|      utf16fix_block_sse<big_endian, false>(out + i, in + i);
  132|     23|    }
  133|       |
  134|    129|    utf16fix_block_sse<big_endian, false>(out + n - 8, in + n - 8);
  135|    129|  }
  136|       |
  137|    129|  out[n - 1] = scalar::utf16::is_high_surrogate<big_endian>(out[n - 1])
  ------------------
  |  Branch (137:16): [True: 20, False: 109]
  ------------------
  138|    129|                   ? replacement
  139|    129|                   : out[n - 1];
  140|    129|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDs:
   72|    152|void utf16fix_block_sse(char16_t *out, const char16_t *in) {
   73|    152|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    152|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    152|  };
   76|    152|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   77|    152|  __m128i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   78|    152|  __m128i illseq, lb_illseq, block_illseq;
   79|       |
   80|    152|  lookback = _mm_loadu_si128((const __m128i *)(in - 1));
   81|    152|  block = _mm_loadu_si128((const __m128i *)in);
   82|    152|  lb_masked = _mm_and_si128(lookback, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   83|    152|  block_masked = _mm_and_si128(block, _mm_set1_epi16(swap_if_needed(0xfc00U)));
   84|    152|  lb_is_high =
   85|    152|      _mm_cmpeq_epi16(lb_masked, _mm_set1_epi16(swap_if_needed(0xd800U)));
   86|    152|  block_is_low =
   87|    152|      _mm_cmpeq_epi16(block_masked, _mm_set1_epi16(swap_if_needed(0xdc00U)));
   88|       |
   89|    152|  illseq = _mm_xor_si128(lb_is_high, block_is_low);
   90|    152|  if (_mm_movemask_epi8(illseq) != 0) {
  ------------------
  |  Branch (90:7): [True: 95, False: 57]
  ------------------
   91|       |    /* compute the cause of the illegal sequencing */
   92|     95|    lb_illseq = _mm_andnot_si128(block_is_low, lb_is_high);
   93|     95|    block_illseq = _mm_or_si128(_mm_andnot_si128(lb_is_high, block_is_low),
   94|     95|                                _mm_bsrli_si128(lb_illseq, 2));
   95|       |    /* fix illegal sequencing in the lookback */
   96|     95|    int lb = _mm_cvtsi128_si32(lb_illseq);
   97|     95|    lb = (lb & replacement) | (~lb & out[-1]);
   98|     95|    out[-1] = char16_t(lb);
   99|       |    /* fix illegal sequencing in the main block */
  100|     95|    block =
  101|     95|        _mm_or_si128(_mm_andnot_si128(block_illseq, block),
  102|     95|                     _mm_and_si128(block_illseq, _mm_set1_epi16(replacement)));
  103|     95|    _mm_storeu_si128((__m128i *)out, block);
  104|     95|  } else if (!in_place) {
  ------------------
  |  Branch (104:14): [True: 57, Folded]
  ------------------
  105|     57|    _mm_storeu_si128((__m128i *)out, block);
  106|     57|  }
  107|    152|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_118utf16fix_block_sseILNS_10endiannessE1ELb0EEEvPDsPKDsENKUltE_clEt:
   73|    608|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   74|    608|    return scalar::utf16::swap_if_needed<big_endian>(x);
   75|    608|  };
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE1ELb0EEEvPDsPKDs:
   10|   479k|void utf16fix_block(char16_t *out, const char16_t *in) {
   11|   479k|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|   479k|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|   479k|  };
   14|   479k|  const char16_t replacement = scalar::utf16::replacement<big_endian>();
   15|   479k|  __m256i lookback, block, lb_masked, block_masked, lb_is_high, block_is_low;
   16|   479k|  __m256i illseq, lb_illseq, block_illseq, lb_illseq_shifted;
   17|       |
   18|   479k|  lookback = _mm256_loadu_si256((const __m256i *)(in - 1));
   19|   479k|  block = _mm256_loadu_si256((const __m256i *)in);
   20|   479k|  lb_masked =
   21|   479k|      _mm256_and_si256(lookback, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   22|   479k|  block_masked =
   23|   479k|      _mm256_and_si256(block, _mm256_set1_epi16(swap_if_needed(0xfc00u)));
   24|   479k|  lb_is_high =
   25|   479k|      _mm256_cmpeq_epi16(lb_masked, _mm256_set1_epi16(swap_if_needed(0xd800u)));
   26|   479k|  block_is_low = _mm256_cmpeq_epi16(block_masked,
   27|   479k|                                    _mm256_set1_epi16(swap_if_needed(0xdc00u)));
   28|       |
   29|   479k|  illseq = _mm256_xor_si256(lb_is_high, block_is_low);
   30|   479k|  if (!_mm256_testz_si256(illseq, illseq)) {
  ------------------
  |  Branch (30:7): [True: 38.2k, False: 441k]
  ------------------
   31|  38.2k|    int lb;
   32|       |
   33|       |    /* compute the cause of the illegal sequencing */
   34|  38.2k|    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|  38.2k|    lb_illseq_shifted =
   45|  38.2k|        _mm256_or_si256(_mm256_bsrli_epi128(lb_illseq, 2),
   46|  38.2k|                        _mm256_zextsi128_si256(_mm_bslli_si128(
   47|  38.2k|                            _mm256_extracti128_si256(lb_illseq, 1), 14)));
   48|  38.2k|#endif // SIMDUTF_GCC9OROLDER
   49|  38.2k|    block_illseq = _mm256_or_si256(
   50|  38.2k|        _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|  38.2k|    lb = _mm256_cvtsi256_si32(lb_illseq);
   58|  38.2k|#endif
   59|  38.2k|    lb = (lb & replacement) | (~lb & out[-1]);
   60|  38.2k|    out[-1] = char16_t(lb);
   61|       |
   62|       |    /* fix illegal sequencing in the main block */
   63|  38.2k|    block =
   64|  38.2k|        _mm256_blendv_epi8(block, _mm256_set1_epi16(replacement), block_illseq);
   65|  38.2k|    _mm256_storeu_si256((__m256i *)out, block);
   66|   441k|  } else if (!in_place) {
  ------------------
  |  Branch (66:14): [True: 441k, Folded]
  ------------------
   67|   441k|    _mm256_storeu_si256((__m256i *)out, block);
   68|   441k|  }
   69|   479k|}
simdutf.cpp:_ZZN7simdutf7haswell12_GLOBAL__N_114utf16fix_blockILNS_10endiannessE1ELb0EEEvPDsPKDsENKUltE_clEt:
   11|  1.91M|  auto swap_if_needed = [](uint16_t x) constexpr -> uint16_t {
   12|  1.91M|    return scalar::utf16::swap_if_needed<big_endian>(x);
   13|  1.91M|  };

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

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

_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.01k|    const char *input, size_t length) const noexcept {
   75|       |  // If there is a BOM, then we trust it.
   76|  2.01k|  auto bom_encoding = simdutf::BOM::check_bom(input, length);
   77|  2.01k|  if (bom_encoding != encoding_type::unspecified) {
  ------------------
  |  Branch (77:7): [True: 111, False: 1.89k]
  ------------------
   78|    111|    return bom_encoding;
   79|    111|  }
   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.89k|  if (validate_utf8(input, length)) {
  ------------------
  |  Branch (87:7): [True: 288, False: 1.61k]
  ------------------
   88|    288|    return encoding_type::UTF8;
   89|    288|  }
   90|       |  // The next most common encoding that might appear without BOM is probably
   91|       |  // UTF-16LE, so try that next.
   92|  1.61k|  if ((length % 2) == 0) {
  ------------------
  |  Branch (92:7): [True: 1.10k, False: 510]
  ------------------
   93|       |    // important: we need to divide by two
   94|  1.10k|    if (validate_utf16le(reinterpret_cast<const char16_t *>(input),
  ------------------
  |  Branch (94:9): [True: 258, False: 843]
  ------------------
   95|  1.10k|                         length / 2)) {
   96|    258|      return encoding_type::UTF16_LE;
   97|    258|    }
   98|  1.10k|  }
   99|  1.35k|  if ((length % 4) == 0) {
  ------------------
  |  Branch (99:7): [True: 723, False: 630]
  ------------------
  100|    723|    if (validate_utf32(reinterpret_cast<const char32_t *>(input), length / 4)) {
  ------------------
  |  Branch (100:9): [True: 84, False: 639]
  ------------------
  101|     84|      return encoding_type::UTF32_LE;
  102|     84|    }
  103|    723|  }
  104|  1.26k|  return encoding_type::unspecified;
  105|  1.35k|}
_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|    545|get_active_implementation() {
 1587|    545|#if !SIMDUTF_USE_STATIC_INITIALIZATION
 1588|    545|  #if !SIMDUTF_SINGLE_IMPLEMENTATION
 1589|    545|  static const internal::detect_best_supported_implementation_on_first_use
 1590|    545|      detect_best_supported_implementation_on_first_use_singleton;
 1591|    545|  #endif
 1592|    545|  static internal::atomic_ptr<const implementation>
 1593|    545|      active_implementation_instance{
 1594|       |  #if SIMDUTF_SINGLE_IMPLEMENTATION
 1595|       |          internal::get_single_implementation()
 1596|       |  #else
 1597|    545|          &detect_best_supported_implementation_on_first_use_singleton
 1598|    545|  #endif
 1599|    545|      };
 1600|    545|#endif
 1601|    545|  return active_implementation_instance;
 1602|    545|}
_ZN7simdutf22convert_latin1_to_utf8EPKcmPc:
 1668|    544|                                                  char *utf8_output) noexcept {
 1669|    544|  return get_default_implementation()->convert_latin1_to_utf8(buf, len,
 1670|    544|                                                              utf8_output);
 1671|    544|}
_ZN7simdutf27convert_latin1_to_utf8_safeEPKcmPcm:
 2568|    261|    const char *buf, size_t len, char *utf8_output, size_t utf8_len) noexcept {
 2569|    261|  const auto start{utf8_output};
 2570|       |
 2571|    544|  while (true) {
  ------------------
  |  Branch (2571:10): [True: 544, Folded]
  ------------------
 2572|       |    // convert_latin1_to_utf8 will never write more than input length * 2
 2573|    544|    auto read_len = detail::min(len, utf8_len >> 1);
 2574|    544|    if (read_len <= 16) {
  ------------------
  |  Branch (2574:9): [True: 261, False: 283]
  ------------------
 2575|    261|      break;
 2576|    261|    }
 2577|       |
 2578|    283|    const auto write_len =
 2579|    283|        simdutf::convert_latin1_to_utf8(buf, read_len, utf8_output);
 2580|       |
 2581|    283|    utf8_output += write_len;
 2582|    283|    utf8_len -= write_len;
 2583|    283|    buf += read_len;
 2584|    283|    len -= read_len;
 2585|    283|  }
 2586|       |
 2587|    261|  utf8_output +=
 2588|    261|      scalar::latin1_to_utf8::convert_safe(buf, len, utf8_output, utf8_len);
 2589|       |
 2590|    261|  return utf8_output - start;
 2591|    261|}
_ZN7simdutf17trim_partial_utf8EPKcm:
 2655|    104|simdutf_warn_unused size_t trim_partial_utf8(const char *input, size_t length) {
 2656|    104|  return scalar::utf8::trim_partial_utf8(input, length);
 2657|    104|}
_ZN7simdutf20trim_partial_utf16beEPKDsm:
 2662|     47|                                                size_t length) {
 2663|     47|  return scalar::utf16::trim_partial_utf16<BIG>(input, length);
 2664|     47|}
_ZN7simdutf20trim_partial_utf16leEPKDsm:
 2667|     42|                                                size_t length) {
 2668|     42|  return scalar::utf16::trim_partial_utf16<LITTLE>(input, length);
 2669|     42|}
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|    544|get_default_implementation() {
 1611|    544|  return get_active_implementation();
 1612|    544|}

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_115trailing_zeroesEm:
   20|    335|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|    335|  return __builtin_ctzll(input_num);
   25|    335|  #endif // SIMDUTF_REGULAR_VISUAL_STUDIO
   26|    335|}

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

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

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

_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|    335|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|    335|  return __builtin_ctzll(input_num);
   27|    335|  #endif // SIMDUTF_REGULAR_VISUAL_STUDIO
   28|    335|}

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

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

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

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

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

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

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

