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

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

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

_ZNK7simdutf14implementation4nameEv:
 5092|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5143|     10|  virtual uint32_t required_instruction_sets() const {
 5144|     10|    return _required_instruction_sets;
 5145|     10|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7029|      5|      : _name(name), _description(description),
 7030|      5|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7061|      1|  simdutf_really_inline available_implementation_list() {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEaSEPS3_:
 7132|      1|  atomic_ptr &operator=(T *_ptr) {
 7133|      1|    ptr = _ptr;
 7134|      1|    return *this;
 7135|      1|  }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEcvPS3_Ev:
 7129|      1|  operator T *() { return ptr.load(); }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEC2EPS3_:
 7109|      1|  atomic_ptr(T *_ptr) : ptr{_ptr} {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEptEv:
 7131|    570|  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:
   14|    208|                                                      size_t len) noexcept {
   15|    208|  uint64_t pos = 0;
   16|       |
   17|       |#if SIMDUTF_CPLUSPLUS23
   18|       |  // avoid memcpy during constant evaluation
   19|       |  if !consteval
   20|       |#endif
   21|       |  // process in blocks of 16 bytes when possible
   22|    208|  {
   23|   174k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (23:12): [True: 174k, False: 86]
  ------------------
   24|   174k|      uint64_t v1;
   25|   174k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   26|   174k|      uint64_t v2;
   27|   174k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   28|   174k|      uint64_t v{v1 | v2};
   29|   174k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (29:11): [True: 122, False: 174k]
  ------------------
   30|    122|        return false;
   31|    122|      }
   32|   174k|    }
   33|    208|  }
   34|       |
   35|       |  // process the tail byte-by-byte
   36|    429|  for (; pos < len; pos++) {
  ------------------
  |  Branch (36:10): [True: 381, False: 48]
  ------------------
   37|    381|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (37:9): [True: 38, False: 343]
  ------------------
   38|     38|      return false;
   39|     38|    }
   40|    381|  }
   41|     48|  return true;
   42|     86|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_15ascii20validate_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_m:
   48|    793|validate_with_errors(InputPtr data, size_t len) noexcept {
   49|    793|  size_t pos = 0;
   50|       |#if SIMDUTF_CPLUSPLUS23
   51|       |  // avoid memcpy during constant evaluation
   52|       |  if !consteval
   53|       |#endif
   54|    793|  {
   55|       |    // process in blocks of 16 bytes when possible
   56|   238k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (56:12): [True: 237k, False: 175]
  ------------------
   57|   237k|      uint64_t v1;
   58|   237k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   59|   237k|      uint64_t v2;
   60|   237k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   61|   237k|      uint64_t v{v1 | v2};
   62|   237k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (62:11): [True: 618, False: 237k]
  ------------------
   63|  3.39k|        for (; pos < len; pos++) {
  ------------------
  |  Branch (63:16): [True: 3.39k, False: 0]
  ------------------
   64|  3.39k|          if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (64:15): [True: 618, False: 2.77k]
  ------------------
   65|    618|            return result(error_code::TOO_LARGE, pos);
   66|    618|          }
   67|  3.39k|        }
   68|    618|      }
   69|   237k|    }
   70|    793|  }
   71|       |
   72|       |  // process the tail byte-by-byte
   73|    652|  for (; pos < len; pos++) {
  ------------------
  |  Branch (73:10): [True: 618, False: 34]
  ------------------
   74|    618|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (74:9): [True: 141, False: 477]
  ------------------
   75|    141|      return result(error_code::TOO_LARGE, pos);
   76|    141|    }
   77|    618|  }
   78|     34|  return result(error_code::SUCCESS, pos);
   79|    175|}

simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf812convert_safeEPKcmPcm:
   70|    295|                           size_t utf8_len) {
   71|    295|  const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   72|    295|  size_t pos = 0;
   73|    295|  size_t skip_pos = 0;
   74|    295|  size_t utf8_pos = 0;
   75|  1.52k|  while (pos < len && utf8_pos < utf8_len) {
  ------------------
  |  Branch (75:10): [True: 1.36k, False: 161]
  |  Branch (75:23): [True: 1.27k, False: 94]
  ------------------
   76|       |    // try to convert the next block of 16 ASCII bytes
   77|  1.27k|    if (pos >= skip_pos && pos + 16 <= len &&
  ------------------
  |  Branch (77:9): [True: 731, False: 541]
  |  Branch (77:28): [True: 396, False: 335]
  ------------------
   78|    396|        utf8_pos + 16 <= utf8_len) { // if it is safe to read 16 more bytes,
  ------------------
  |  Branch (78:9): [True: 84, False: 312]
  ------------------
   79|       |                                     // check that they are ascii
   80|     84|      uint64_t v1;
   81|     84|      ::memcpy(&v1, data + pos, sizeof(uint64_t));
   82|     84|      uint64_t v2;
   83|     84|      ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   84|     84|      uint64_t v{v1 |
   85|     84|                 v2}; // We are only interested in these bits: 1000 1000 1000
   86|       |                      // 1000, so it makes sense to concatenate everything
   87|     84|      if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (87:11): [True: 49, False: 35]
  ------------------
   88|     84|          0) { // if NONE of these are set, e.g. all of them are zero, then
   89|       |               // everything is ASCII
   90|     49|        ::memcpy(utf8_output + utf8_pos, buf + pos, 16);
   91|     49|        utf8_pos += 16;
   92|     49|        pos += 16;
   93|     49|      } else {
   94|       |        // At least one of the next 16 bytes are not ASCII, we will process them
   95|       |        // one by one
   96|     35|        skip_pos = pos + 16;
   97|     35|      }
   98|  1.18k|    } else {
   99|  1.18k|      const auto byte = data[pos];
  100|  1.18k|      if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (100:11): [True: 740, False: 448]
  ------------------
  101|       |        // will generate one UTF-8 bytes
  102|    740|        utf8_output[utf8_pos++] = char(byte);
  103|    740|        pos++;
  104|    740|      } else if (utf8_pos + 2 <= utf8_len) {
  ------------------
  |  Branch (104:18): [True: 408, False: 40]
  ------------------
  105|       |        // will generate two UTF-8 bytes
  106|    408|        utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
  107|    408|        utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
  108|    408|        pos++;
  109|    408|      } else {
  110|     40|        break;
  111|     40|      }
  112|  1.18k|    }
  113|  1.27k|  }
  114|    295|  return utf8_pos;
  115|    295|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertEPKcmPc:
   64|    539|                                     char *utf8_output) {
   65|    539|  return convert(reinterpret_cast<const unsigned char *>(buf), len,
   66|    539|                 utf8_output);
   67|    539|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_114latin1_to_utf87convertIPKhPcQaasr7simdutf6detailE22indexes_into_byte_likeIT_Esr7simdutf6detailE26index_assignable_from_charIT0_EEEmS7_mS8_:
   15|    539|                                   OutputPtr utf8_output) {
   16|       |  // const unsigned char *data = reinterpret_cast<const unsigned char *>(buf);
   17|    539|  size_t pos = 0;
   18|    539|  size_t utf8_pos = 0;
   19|       |
   20|  7.33k|  while (pos < len) {
  ------------------
  |  Branch (20:10): [True: 6.79k, False: 539]
  ------------------
   21|       |#if SIMDUTF_CPLUSPLUS23
   22|       |    if !consteval
   23|       |#endif
   24|  6.79k|    {
   25|       |      // try to convert the next block of 16 ASCII bytes
   26|  6.79k|      if (pos + 16 <= len) { // if it is safe to read 16 more bytes, check that
  ------------------
  |  Branch (26:11): [True: 1.10k, False: 5.68k]
  ------------------
   27|       |                             // they are ascii
   28|  1.10k|        uint64_t v1;
   29|  1.10k|        ::memcpy(&v1, data + pos, sizeof(uint64_t));
   30|  1.10k|        uint64_t v2;
   31|  1.10k|        ::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   32|  1.10k|        uint64_t v{v1 |
   33|  1.10k|                   v2}; // We are only interested in these bits: 1000 1000 1000
   34|       |                        // 1000, so it makes sense to concatenate everything
   35|  1.10k|        if ((v & 0x8080808080808080) ==
  ------------------
  |  Branch (35:13): [True: 128, False: 980]
  ------------------
   36|  1.10k|            0) { // if NONE of these are set, e.g. all of them are zero, then
   37|       |                 // everything is ASCII
   38|    128|          size_t final_pos = pos + 16;
   39|  2.17k|          while (pos < final_pos) {
  ------------------
  |  Branch (39:18): [True: 2.04k, False: 128]
  ------------------
   40|  2.04k|            utf8_output[utf8_pos++] = char(data[pos]);
   41|  2.04k|            pos++;
   42|  2.04k|          }
   43|    128|          continue;
   44|    128|        }
   45|  1.10k|      } // if (pos + 16 <= len)
   46|  6.79k|    } // !consteval scope
   47|       |
   48|  6.66k|    unsigned char byte = data[pos];
   49|  6.66k|    if ((byte & 0x80) == 0) { // if ASCII
  ------------------
  |  Branch (49:9): [True: 2.67k, False: 3.99k]
  ------------------
   50|       |      // will generate one UTF-8 bytes
   51|  2.67k|      utf8_output[utf8_pos++] = char(byte);
   52|  2.67k|      pos++;
   53|  3.99k|    } else {
   54|       |      // will generate two UTF-8 bytes
   55|  3.99k|      utf8_output[utf8_pos++] = char((byte >> 6) | 0b11000000);
   56|  3.99k|      utf8_output[utf8_pos++] = char((byte & 0b111111) | 0b10000000);
   57|  3.99k|      pos++;
   58|  3.99k|    }
   59|  6.66k|  } // while
   60|    539|  return utf8_pos;
   61|    539|}

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

_ZN7simdutf6scalar5utf1623change_endianness_utf16EPKDsmPDs:
  119|    399|change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) {
  120|  2.69M|  for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (120:22): [True: 2.69M, False: 399]
  ------------------
  121|  2.69M|    *output++ = char16_t(input[i] >> 8 | input[i] << 8);
  122|  2.69M|  }
  123|    399|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE1EEEmPKDsm:
  127|     41|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     41|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 40]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     40|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     40|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     40|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     40|  return length;
  135|     41|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE0EEEmPKDsm:
  127|     28|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     28|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 27]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     27|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     27|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     27|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     27|  return length;
  135|     28|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE0EEEbPKDsm:
   10|    230|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  14.1k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 14.1k, False: 22]
  ------------------
   12|  14.1k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  14.1k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 208, False: 13.9k]
  ------------------
   14|    208|      return false;
   15|    208|    }
   16|  14.1k|  }
   17|     22|  return true;
   18|    230|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE1EEEbPKDsm:
   10|    230|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  17.9k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 17.9k, False: 24]
  ------------------
   12|  17.9k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  17.9k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 206, False: 17.7k]
  ------------------
   14|    206|      return false;
   15|    206|    }
   16|  17.9k|  }
   17|     24|  return true;
   18|    230|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE0EEEbPKDsm:
   22|  4.15k|validate(const char16_t *data, size_t len) noexcept {
   23|  4.15k|  uint64_t pos = 0;
   24|  13.7M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 13.7M, False: 2.94k]
  ------------------
   25|  13.7M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  13.7M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 25.6k, False: 13.6M]
  ------------------
   27|  25.6k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 242, False: 25.4k]
  ------------------
   28|    242|        return false;
   29|    242|      }
   30|  25.4k|      char16_t diff = char16_t(word - 0xD800);
   31|  25.4k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 450, False: 24.9k]
  ------------------
   32|    450|        return false;
   33|    450|      }
   34|  24.9k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [Folded, False: 24.9k]
  ------------------
   35|  24.9k|                               ? u16_swap_bytes(data[pos + 1])
   36|  24.9k|                               : data[pos + 1];
   37|  24.9k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  24.9k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 516, False: 24.4k]
  ------------------
   39|    516|        return false;
   40|    516|      }
   41|  24.4k|      pos += 2;
   42|  13.6M|    } else {
   43|  13.6M|      pos++;
   44|  13.6M|    }
   45|  13.7M|  }
   46|  2.94k|  return true;
   47|  4.15k|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE1EEEbPKDsm:
   22|  2.70k|validate(const char16_t *data, size_t len) noexcept {
   23|  2.70k|  uint64_t pos = 0;
   24|  8.15M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 8.15M, False: 2.43k]
  ------------------
   25|  8.15M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  8.15M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 23.1k, False: 8.12M]
  ------------------
   27|  23.1k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 50, False: 23.0k]
  ------------------
   28|     50|        return false;
   29|     50|      }
   30|  23.0k|      char16_t diff = char16_t(word - 0xD800);
   31|  23.0k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 103, False: 22.9k]
  ------------------
   32|    103|        return false;
   33|    103|      }
   34|  22.9k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [True: 22.9k, Folded]
  ------------------
   35|  22.9k|                               ? u16_swap_bytes(data[pos + 1])
   36|  22.9k|                               : data[pos + 1];
   37|  22.9k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  22.9k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 121, False: 22.8k]
  ------------------
   39|    121|        return false;
   40|    121|      }
   41|  22.8k|      pos += 2;
   42|  8.12M|    } else {
   43|  8.12M|      pos++;
   44|  8.12M|    }
   45|  8.15M|  }
   46|  2.43k|  return true;
   47|  2.70k|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE0EEEvPKDsmPDs:
  190|  1.01k|                                              char16_t *output) {
  191|  1.01k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.01k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.01k|  size_t i = 0;
  194|  8.13M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.13M, False: 1.01k]
  ------------------
  195|  8.13M|    char16_t c = input[i];
  196|  8.13M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.13M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.13M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 45.1k, False: 8.08M]
  |  Branch (198:32): [True: 24.9k, False: 20.1k]
  ------------------
  199|  24.9k|      output[i - 1] = replacement;
  200|  24.9k|    }
  201|       |
  202|  8.13M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.08M, False: 45.1k]
  |  Branch (202:33): [True: 437k, False: 7.64M]
  ------------------
  203|   437k|      output[i] = replacement;
  204|  7.69M|    } else {
  205|  7.69M|      output[i] = input[i];
  206|  7.69M|    }
  207|  8.13M|    high_surrogate_prev = high_surrogate;
  208|  8.13M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.01k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 124, False: 894]
  ------------------
  212|    124|    output[i - 1] = replacement;
  213|    124|  }
  214|  1.01k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  8.13M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.13M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.13M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 743k, False: 7.38M]
  |  Branch (139:26): [True: 45.3k, False: 698k]
  ------------------
  140|  8.13M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  8.13M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.13M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.13M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 698k, False: 7.43M]
  |  Branch (144:26): [True: 458k, False: 240k]
  ------------------
  145|  8.13M|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE1EEEvPKDsmPDs:
  190|  1.01k|                                              char16_t *output) {
  191|  1.01k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.01k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.01k|  size_t i = 0;
  194|  8.13M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.13M, False: 1.01k]
  ------------------
  195|  8.13M|    char16_t c = input[i];
  196|  8.13M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.13M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.13M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 46.4k, False: 8.08M]
  |  Branch (198:32): [True: 25.0k, False: 21.4k]
  ------------------
  199|  25.0k|      output[i - 1] = replacement;
  200|  25.0k|    }
  201|       |
  202|  8.13M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.08M, False: 46.4k]
  |  Branch (202:33): [True: 437k, False: 7.64M]
  ------------------
  203|   437k|      output[i] = replacement;
  204|  7.69M|    } else {
  205|  7.69M|      output[i] = input[i];
  206|  7.69M|    }
  207|  8.13M|    high_surrogate_prev = high_surrogate;
  208|  8.13M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.01k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 130, False: 888]
  ------------------
  212|    130|    output[i - 1] = replacement;
  213|    130|  }
  214|  1.01k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  8.13M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.13M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.13M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 749k, False: 7.38M]
  |  Branch (139:26): [True: 46.6k, False: 703k]
  ------------------
  140|  8.13M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  8.13M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.13M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.13M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 703k, False: 7.42M]
  |  Branch (144:26): [True: 459k, False: 243k]
  ------------------
  145|  8.13M|}

_ZN7simdutf6scalar5utf328validateEPKDim:
   25|    794|                                                        size_t len) noexcept {
   26|    794|  return validate(reinterpret_cast<const uint32_t *>(buf), len);
   27|    794|}
_ZN7simdutf6scalar5utf328validateIPKjQsr7simdutf6detailE19indexes_into_uint32IT_EEEbS5_m:
   13|    794|                                                      size_t len) noexcept {
   14|    794|  uint64_t pos = 0;
   15|  3.91k|  for (; pos < len; pos++) {
  ------------------
  |  Branch (15:10): [True: 3.76k, False: 154]
  ------------------
   16|  3.76k|    uint32_t word = data[pos];
   17|  3.76k|    if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) {
  ------------------
  |  Branch (17:9): [True: 564, False: 3.19k]
  |  Branch (17:29): [True: 860, False: 2.33k]
  |  Branch (17:47): [True: 76, False: 784]
  ------------------
   18|    640|      return false;
   19|    640|    }
   20|  3.76k|  }
   21|    154|  return true;
   22|    794|}

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

_ZN7simdutf3BOM9check_bomEPKhm:
   24|  4.06k|encoding_type check_bom(const uint8_t *byte, size_t length) {
   25|  4.06k|  if (length >= 2 && byte[0] == 0xff and byte[1] == 0xfe) {
  ------------------
  |  Branch (25:7): [True: 4.01k, False: 57]
  |  Branch (25:22): [True: 555, False: 3.45k]
  |  Branch (25:42): [True: 222, False: 333]
  ------------------
   26|    222|    if (length >= 4 && byte[2] == 0x00 and byte[3] == 0x0) {
  ------------------
  |  Branch (26:9): [True: 210, False: 12]
  |  Branch (26:24): [True: 84, False: 126]
  |  Branch (26:44): [True: 24, False: 60]
  ------------------
   27|     24|      return encoding_type::UTF32_LE;
   28|    198|    } else {
   29|    198|      return encoding_type::UTF16_LE;
   30|    198|    }
   31|  3.84k|  } else if (length >= 2 && byte[0] == 0xfe and byte[1] == 0xff) {
  ------------------
  |  Branch (31:14): [True: 3.78k, False: 57]
  |  Branch (31:29): [True: 102, False: 3.68k]
  |  Branch (31:49): [True: 6, False: 96]
  ------------------
   32|      6|    return encoding_type::UTF16_BE;
   33|  3.84k|  } else if (length >= 4 && byte[0] == 0x00 and byte[1] == 0x00 and
  ------------------
  |  Branch (33:14): [True: 3.25k, False: 585]
  |  Branch (33:29): [True: 1.02k, False: 2.23k]
  |  Branch (33:49): [True: 645, False: 375]
  ------------------
   34|    645|             byte[2] == 0xfe and byte[3] == 0xff) {
  ------------------
  |  Branch (34:14): [True: 90, False: 555]
  |  Branch (34:34): [True: 6, False: 84]
  ------------------
   35|      6|    return encoding_type::UTF32_BE;
   36|  3.83k|  } else if (length >= 3 && byte[0] == 0xef and byte[1] == 0xbb and
  ------------------
  |  Branch (36:14): [True: 3.51k, False: 315]
  |  Branch (36:29): [True: 297, False: 3.22k]
  |  Branch (36:49): [True: 123, False: 174]
  ------------------
   37|    123|             byte[2] == 0xbf) {
  ------------------
  |  Branch (37:14): [True: 6, False: 117]
  ------------------
   38|      6|    return encoding_type::UTF8;
   39|      6|  }
   40|  3.82k|  return encoding_type::unspecified;
   41|  4.06k|}
_ZN7simdutf3BOM9check_bomEPKcm:
   43|  4.06k|encoding_type check_bom(const char *byte, size_t length) {
   44|  4.06k|  return check_bom(reinterpret_cast<const uint8_t *>(byte), length);
   45|  4.06k|}

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

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

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

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

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

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 2, False: 228]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    228|  size_t pos = 0;
  135|    620|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 564, False: 56]
  ------------------
  136|    564|    simd16x32<uint16_t> input_vec(
  137|    564|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    564|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    564|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 172, False: 392]
  ------------------
  143|       |      // Found a match, return the first one
  144|    172|      int index = trailing_zeroes(~matches) / 2;
  145|    172|      return result(error_code::TOO_LARGE, pos + index);
  146|    172|    }
  147|    564|  }
  148|       |
  149|       |  // Scalar tail
  150|    174|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 154, False: 20]
  ------------------
  151|       |
  152|    154|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    154|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 36, False: 118]
  ------------------
  154|     36|      return result(error_code::TOO_LARGE, pos);
  155|     36|    }
  156|    118|    pos++;
  157|    118|  }
  158|     20|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 2, False: 228]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    228|  size_t pos = 0;
  135|    745|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 685, False: 60]
  ------------------
  136|    685|    simd16x32<uint16_t> input_vec(
  137|    685|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    685|    if constexpr (!match_system(big_endian)) {
  139|    685|      input_vec.swap_bytes();
  140|    685|    }
  141|    685|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    685|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 168, False: 517]
  ------------------
  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|    685|  }
  148|       |
  149|       |  // Scalar tail
  150|    171|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 149, False: 22]
  ------------------
  151|       |
  152|    149|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    149|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 38, False: 111]
  ------------------
  154|     38|      return result(error_code::TOO_LARGE, pos);
  155|     38|    }
  156|    111|    pos++;
  157|    111|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     60|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.85k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.85k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|  1.85k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 0, False: 1.85k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.85k|  const char16_t *start = input;
   55|  1.85k|  const char16_t *end = input + size;
   56|       |
   57|  1.85k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.85k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.85k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.85k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   807k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 805k, False: 1.58k]
  ------------------
   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|   805k|    auto in0 = simd16<uint16_t>(input);
   67|   805k|    auto in1 =
   68|   805k|        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|   805k|    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|   805k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   805k|    const uint16_t surrogates_bitmask =
   77|   805k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   805k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 793k, False: 11.8k]
  ------------------
   79|   793k|      input += 16;
   80|   793k|    } 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|  11.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|  11.8k|      const auto vH = (in & v_fc) == v_dc;
   93|  11.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|  11.8k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  11.8k|      const uint16_t a = static_cast<uint16_t>(
  100|  11.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|  11.8k|      const uint16_t b = static_cast<uint16_t>(
  104|  11.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|  11.8k|      const uint16_t c = static_cast<uint16_t>(
  107|  11.8k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  11.8k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 9.64k, False: 2.21k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  9.64k|        input += 16;
  113|  9.64k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.95k, False: 262]
  ------------------
  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.95k|        input += 15;
  119|  1.95k|      } else {
  120|    262|        return result(error_code::SURROGATE, input - start);
  121|    262|      }
  122|  11.8k|    }
  123|   805k|  }
  124|       |
  125|  1.58k|  return result(error_code::SUCCESS, input - start);
  126|  1.85k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|  1.44k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.44k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|  1.44k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 0, False: 1.44k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.44k|  const char16_t *start = input;
   55|  1.44k|  const char16_t *end = input + size;
   56|       |
   57|  1.44k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.44k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.44k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.44k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   539k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 537k, False: 1.23k]
  ------------------
   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|   537k|    auto in0 = simd16<uint16_t>(input);
   67|   537k|    auto in1 =
   68|   537k|        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|   537k|    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|   537k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   537k|    const uint16_t surrogates_bitmask =
   77|   537k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   537k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 526k, False: 11.0k]
  ------------------
   79|   526k|      input += 16;
   80|   526k|    } 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|  11.0k|      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|  11.0k|      const auto vH = (in & v_fc) == v_dc;
   93|  11.0k|      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|  11.0k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  11.0k|      const uint16_t a = static_cast<uint16_t>(
  100|  11.0k|          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|  11.0k|      const uint16_t b = static_cast<uint16_t>(
  104|  11.0k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  11.0k|      const uint16_t c = static_cast<uint16_t>(
  107|  11.0k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  11.0k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 8.80k, False: 2.22k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  8.80k|        input += 16;
  113|  8.80k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 2.02k, False: 201]
  ------------------
  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.02k|        input += 15;
  119|  2.02k|      } else {
  120|    201|        return result(error_code::SURROGATE, input - start);
  121|    201|      }
  122|  11.0k|    }
  123|   537k|  }
  124|       |
  125|  1.23k|  return result(error_code::SUCCESS, input - start);
  126|  1.44k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 2, False: 228]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    228|  size_t pos = 0;
  135|    620|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 564, False: 56]
  ------------------
  136|    564|    simd16x32<uint16_t> input_vec(
  137|    564|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    564|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    564|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 172, False: 392]
  ------------------
  143|       |      // Found a match, return the first one
  144|    172|      int index = trailing_zeroes(~matches) / 2;
  145|    172|      return result(error_code::TOO_LARGE, pos + index);
  146|    172|    }
  147|    564|  }
  148|       |
  149|       |  // Scalar tail
  150|    174|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 154, False: 20]
  ------------------
  151|       |
  152|    154|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    154|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 36, False: 118]
  ------------------
  154|     36|      return result(error_code::TOO_LARGE, pos);
  155|     36|    }
  156|    118|    pos++;
  157|    118|  }
  158|     20|  return result(error_code::SUCCESS, size);
  159|     56|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 2, False: 228]
  |  |  ------------------
  ------------------
  132|      2|    return result(error_code::SUCCESS, 0);
  133|      2|  }
  134|    228|  size_t pos = 0;
  135|    745|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 685, False: 60]
  ------------------
  136|    685|    simd16x32<uint16_t> input_vec(
  137|    685|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    685|    if constexpr (!match_system(big_endian)) {
  139|    685|      input_vec.swap_bytes();
  140|    685|    }
  141|    685|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    685|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 168, False: 517]
  ------------------
  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|    685|  }
  148|       |
  149|       |  // Scalar tail
  150|    171|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 149, False: 22]
  ------------------
  151|       |
  152|    149|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    149|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 38, False: 111]
  ------------------
  154|     38|      return result(error_code::TOO_LARGE, pos);
  155|     38|    }
  156|    111|    pos++;
  157|    111|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     60|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.14k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.14k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|  1.14k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 0, False: 1.14k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.14k|  const char16_t *start = input;
   55|  1.14k|  const char16_t *end = input + size;
   56|       |
   57|  1.14k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.14k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.14k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.14k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   751k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 750k, False: 1.03k]
  ------------------
   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|   750k|    auto in0 = simd16<uint16_t>(input);
   67|   750k|    auto in1 =
   68|   750k|        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|   750k|    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|   750k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   750k|    const uint16_t surrogates_bitmask =
   77|   750k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   750k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 738k, False: 11.3k]
  ------------------
   79|   738k|      input += 16;
   80|   738k|    } 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|  11.3k|      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|  11.3k|      const auto vH = (in & v_fc) == v_dc;
   93|  11.3k|      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|  11.3k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  11.3k|      const uint16_t a = static_cast<uint16_t>(
  100|  11.3k|          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|  11.3k|      const uint16_t b = static_cast<uint16_t>(
  104|  11.3k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  11.3k|      const uint16_t c = static_cast<uint16_t>(
  107|  11.3k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  11.3k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 9.41k, False: 1.94k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  9.41k|        input += 16;
  113|  9.41k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.83k, False: 106]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  1.83k|        input += 15;
  119|  1.83k|      } else {
  120|    106|        return result(error_code::SURROGATE, input - start);
  121|    106|      }
  122|  11.3k|    }
  123|   750k|  }
  124|       |
  125|  1.03k|  return result(error_code::SUCCESS, input - start);
  126|  1.14k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|    731|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|    731|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   92|    731|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (92:33): [True: 0, False: 731]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|    731|  const char16_t *start = input;
   55|    731|  const char16_t *end = input + size;
   56|       |
   57|    731|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|    731|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|    731|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|    731|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   508k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 508k, False: 731]
  ------------------
   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|   508k|    auto in0 = simd16<uint16_t>(input);
   67|   508k|    auto in1 =
   68|   508k|        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|   508k|    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|   508k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   508k|    const uint16_t surrogates_bitmask =
   77|   508k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   508k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 497k, False: 10.4k]
  ------------------
   79|   497k|      input += 16;
   80|   497k|    } 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|  10.4k|      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|  10.4k|      const auto vH = (in & v_fc) == v_dc;
   93|  10.4k|      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|  10.4k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  10.4k|      const uint16_t a = static_cast<uint16_t>(
  100|  10.4k|          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|  10.4k|      const uint16_t b = static_cast<uint16_t>(
  104|  10.4k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  10.4k|      const uint16_t c = static_cast<uint16_t>(
  107|  10.4k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  10.4k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 8.58k, False: 1.86k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  8.58k|        input += 16;
  113|  8.58k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.86k, 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.86k|        input += 15;
  119|  1.86k|      } else {
  120|      0|        return result(error_code::SURROGATE, input - start);
  121|      0|      }
  122|  10.4k|    }
  123|   508k|  }
  124|       |
  125|    731|  return result(error_code::SUCCESS, input - start);
  126|    731|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

