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

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

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

_ZNK7simdutf14implementation4nameEv:
 5121|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5172|     10|  virtual uint32_t required_instruction_sets() const {
 5173|     10|    return _required_instruction_sets;
 5174|     10|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7058|      5|      : _name(name), _description(description),
 7059|      5|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7090|      1|  simdutf_really_inline available_implementation_list() {}
simdutf.cpp:_ZN7simdutf6detail12_GLOBAL__N_13minEmm:
   59|    549|constexpr std::size_t min(std::size_t a, std::size_t b) {
   60|    549|  return a < b ? a : b;
  ------------------
  |  Branch (60:10): [True: 148, False: 401]
  ------------------
   61|    549|}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEaSEPS3_:
 7161|      1|  atomic_ptr &operator=(T *_ptr) {
 7162|      1|    ptr = _ptr;
 7163|      1|    return *this;
 7164|      1|  }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEcvPS3_Ev:
 7158|      1|  operator T *() { return ptr.load(); }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEC2EPS3_:
 7138|      1|  atomic_ptr(T *_ptr) : ptr{_ptr} {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEptEv:
 7160|    549|  T *operator->() { return ptr.load(); }

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

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

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

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

_ZN7simdutf6scalar5utf1623change_endianness_utf16EPKDsmPDs:
  119|    390|change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) {
  120|  2.10M|  for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (120:22): [True: 2.10M, False: 390]
  ------------------
  121|  2.10M|    *output++ = char16_t(input[i] >> 8 | input[i] << 8);
  122|  2.10M|  }
  123|    390|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE1EEEmPKDsm:
  127|     47|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     47|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 46]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     46|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     46|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     46|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     46|  return length;
  135|     47|}
_ZN7simdutf6scalar5utf1618trim_partial_utf16ILNS_10endiannessE0EEEmPKDsm:
  127|     43|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     43|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 42]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     42|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     42|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     42|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     42|  return length;
  135|     43|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE0EEEbPKDsm:
   10|    232|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  11.3k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 11.3k, False: 23]
  ------------------
   12|  11.3k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  11.3k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 209, False: 11.1k]
  ------------------
   14|    209|      return false;
   15|    209|    }
   16|  11.3k|  }
   17|     23|  return true;
   18|    232|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE1EEEbPKDsm:
   10|    232|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  11.3k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 11.2k, False: 22]
  ------------------
   12|  11.2k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  11.2k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 210, False: 11.0k]
  ------------------
   14|    210|      return false;
   15|    210|    }
   16|  11.2k|  }
   17|     22|  return true;
   18|    232|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE0EEEbPKDsm:
   22|  3.80k|validate(const char16_t *data, size_t len) noexcept {
   23|  3.80k|  uint64_t pos = 0;
   24|  13.0M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 13.0M, False: 2.68k]
  ------------------
   25|  13.0M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  13.0M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 22.2k, False: 13.0M]
  ------------------
   27|  22.2k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 241, False: 21.9k]
  ------------------
   28|    241|        return false;
   29|    241|      }
   30|  21.9k|      char16_t diff = char16_t(word - 0xD800);
   31|  21.9k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 404, False: 21.5k]
  ------------------
   32|    404|        return false;
   33|    404|      }
   34|  21.5k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [Folded, False: 21.5k]
  ------------------
   35|  21.5k|                               ? u16_swap_bytes(data[pos + 1])
   36|  21.5k|                               : data[pos + 1];
   37|  21.5k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  21.5k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 474, False: 21.1k]
  ------------------
   39|    474|        return false;
   40|    474|      }
   41|  21.1k|      pos += 2;
   42|  13.0M|    } else {
   43|  13.0M|      pos++;
   44|  13.0M|    }
   45|  13.0M|  }
   46|  2.68k|  return true;
   47|  3.80k|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE1EEEbPKDsm:
   22|  2.40k|validate(const char16_t *data, size_t len) noexcept {
   23|  2.40k|  uint64_t pos = 0;
   24|  7.16M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 7.16M, False: 2.17k]
  ------------------
   25|  7.16M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  7.16M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 21.0k, False: 7.14M]
  ------------------
   27|  21.0k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 42, False: 21.0k]
  ------------------
   28|     42|        return false;
   29|     42|      }
   30|  21.0k|      char16_t diff = char16_t(word - 0xD800);
   31|  21.0k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 79, False: 20.9k]
  ------------------
   32|     79|        return false;
   33|     79|      }
   34|  20.9k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [True: 20.9k, Folded]
  ------------------
   35|  20.9k|                               ? u16_swap_bytes(data[pos + 1])
   36|  20.9k|                               : data[pos + 1];
   37|  20.9k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  20.9k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 115, False: 20.8k]
  ------------------
   39|    115|        return false;
   40|    115|      }
   41|  20.8k|      pos += 2;
   42|  7.14M|    } else {
   43|  7.14M|      pos++;
   44|  7.14M|    }
   45|  7.16M|  }
   46|  2.17k|  return true;
   47|  2.40k|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE0EEEvPKDsmPDs:
  190|    921|                                              char16_t *output) {
  191|    921|  const char16_t replacement = utf16::replacement<big_endian>();
  192|    921|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|    921|  size_t i = 0;
  194|  7.15M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 7.14M, False: 921]
  ------------------
  195|  7.14M|    char16_t c = input[i];
  196|  7.14M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  7.14M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  7.14M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 30.2k, False: 7.11M]
  |  Branch (198:32): [True: 11.3k, False: 18.8k]
  ------------------
  199|  11.3k|      output[i - 1] = replacement;
  200|  11.3k|    }
  201|       |
  202|  7.14M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 7.11M, False: 30.2k]
  |  Branch (202:33): [True: 332k, False: 6.78M]
  ------------------
  203|   332k|      output[i] = replacement;
  204|  6.81M|    } else {
  205|  6.81M|      output[i] = input[i];
  206|  6.81M|    }
  207|  7.14M|    high_surrogate_prev = high_surrogate;
  208|  7.14M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|    921|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 140, False: 781]
  ------------------
  212|    140|    output[i - 1] = replacement;
  213|    140|  }
  214|    921|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  7.15M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  7.15M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  7.15M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 539k, False: 6.61M]
  |  Branch (139:26): [True: 30.5k, False: 508k]
  ------------------
  140|  7.15M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  7.15M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  7.15M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  7.15M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 509k, False: 6.64M]
  |  Branch (144:26): [True: 351k, False: 157k]
  ------------------
  145|  7.15M|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE1EEEvPKDsmPDs:
  190|    921|                                              char16_t *output) {
  191|    921|  const char16_t replacement = utf16::replacement<big_endian>();
  192|    921|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|    921|  size_t i = 0;
  194|  7.15M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 7.14M, False: 921]
  ------------------
  195|  7.14M|    char16_t c = input[i];
  196|  7.14M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  7.14M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  7.14M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 30.6k, False: 7.11M]
  |  Branch (198:32): [True: 11.1k, False: 19.5k]
  ------------------
  199|  11.1k|      output[i - 1] = replacement;
  200|  11.1k|    }
  201|       |
  202|  7.14M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 7.11M, False: 30.6k]
  |  Branch (202:33): [True: 333k, False: 6.78M]
  ------------------
  203|   333k|      output[i] = replacement;
  204|  6.81M|    } else {
  205|  6.81M|      output[i] = input[i];
  206|  6.81M|    }
  207|  7.14M|    high_surrogate_prev = high_surrogate;
  208|  7.14M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|    921|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 131, False: 790]
  ------------------
  212|    131|    output[i - 1] = replacement;
  213|    131|  }
  214|    921|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  7.15M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  7.15M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  7.15M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 533k, False: 6.61M]
  |  Branch (139:26): [True: 30.9k, False: 502k]
  ------------------
  140|  7.15M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  7.15M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  7.15M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  7.15M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 502k, False: 6.64M]
  |  Branch (144:26): [True: 352k, False: 149k]
  ------------------
  145|  7.15M|}

_ZN7simdutf6scalar5utf328validateEPKDim:
   25|    803|                                                        size_t len) noexcept {
   26|    803|  return validate(reinterpret_cast<const uint32_t *>(buf), len);
   27|    803|}
_ZN7simdutf6scalar5utf328validateIPKjQsr7simdutf6detailE19indexes_into_uint32IT_EEEbS5_m:
   13|    803|                                                      size_t len) noexcept {
   14|    803|  uint64_t pos = 0;
   15|  21.8k|  for (; pos < len; pos++) {
  ------------------
  |  Branch (15:10): [True: 21.6k, False: 158]
  ------------------
   16|  21.6k|    uint32_t word = data[pos];
   17|  21.6k|    if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) {
  ------------------
  |  Branch (17:9): [True: 557, False: 21.1k]
  |  Branch (17:29): [True: 1.09k, False: 20.0k]
  |  Branch (17:47): [True: 88, False: 1.01k]
  ------------------
   18|    645|      return false;
   19|    645|    }
   20|  21.6k|  }
   21|    158|  return true;
   22|    803|}

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

_ZN7simdutf3BOM9check_bomEPKhm:
   24|  4.02k|encoding_type check_bom(const uint8_t *byte, size_t length) {
   25|  4.02k|  if (length >= 2 && byte[0] == 0xff and byte[1] == 0xfe) {
  ------------------
  |  Branch (25:7): [True: 3.95k, False: 63]
  |  Branch (25:22): [True: 450, False: 3.50k]
  |  Branch (25:42): [True: 210, False: 240]
  ------------------
   26|    210|    if (length >= 4 && byte[2] == 0x00 and byte[3] == 0x0) {
  ------------------
  |  Branch (26:9): [True: 198, False: 12]
  |  Branch (26:24): [True: 81, False: 117]
  |  Branch (26:44): [True: 18, False: 63]
  ------------------
   27|     18|      return encoding_type::UTF32_LE;
   28|    192|    } else {
   29|    192|      return encoding_type::UTF16_LE;
   30|    192|    }
   31|  3.81k|  } else if (length >= 2 && byte[0] == 0xfe and byte[1] == 0xff) {
  ------------------
  |  Branch (31:14): [True: 3.74k, False: 63]
  |  Branch (31:29): [True: 111, False: 3.63k]
  |  Branch (31:49): [True: 6, False: 105]
  ------------------
   32|      6|    return encoding_type::UTF16_BE;
   33|  3.80k|  } else if (length >= 4 && byte[0] == 0x00 and byte[1] == 0x00 and
  ------------------
  |  Branch (33:14): [True: 3.19k, False: 609]
  |  Branch (33:29): [True: 1.05k, False: 2.13k]
  |  Branch (33:49): [True: 642, False: 414]
  ------------------
   34|    642|             byte[2] == 0xfe and byte[3] == 0xff) {
  ------------------
  |  Branch (34:14): [True: 72, False: 570]
  |  Branch (34:34): [True: 6, False: 66]
  ------------------
   35|      6|    return encoding_type::UTF32_BE;
   36|  3.79k|  } else if (length >= 3 && byte[0] == 0xef and byte[1] == 0xbb and
  ------------------
  |  Branch (36:14): [True: 3.48k, False: 318]
  |  Branch (36:29): [True: 297, False: 3.18k]
  |  Branch (36:49): [True: 117, False: 180]
  ------------------
   37|    117|             byte[2] == 0xbf) {
  ------------------
  |  Branch (37:14): [True: 6, False: 111]
  ------------------
   38|      6|    return encoding_type::UTF8;
   39|      6|  }
   40|  3.79k|  return encoding_type::unspecified;
   41|  4.02k|}
_ZN7simdutf3BOM9check_bomEPKcm:
   43|  4.02k|encoding_type check_bom(const char *byte, size_t length) {
   44|  4.02k|  return check_bom(reinterpret_cast<const uint8_t *>(byte), length);
   45|  4.02k|}

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

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

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

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

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

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    232|                                                 size_t size) {
  131|    232|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    232|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 231]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    231|  size_t pos = 0;
  135|    537|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 483, False: 54]
  ------------------
  136|    483|    simd16x32<uint16_t> input_vec(
  137|    483|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    483|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    483|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 177, False: 306]
  ------------------
  143|       |      // Found a match, return the first one
  144|    177|      int index = trailing_zeroes(~matches) / 2;
  145|    177|      return result(error_code::TOO_LARGE, pos + index);
  146|    177|    }
  147|    483|  }
  148|       |
  149|       |  // Scalar tail
  150|    143|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 121, False: 22]
  ------------------
  151|       |
  152|    121|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    121|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 32, False: 89]
  ------------------
  154|     32|      return result(error_code::TOO_LARGE, pos);
  155|     32|    }
  156|     89|    pos++;
  157|     89|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     54|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    232|                                                 size_t size) {
  131|    232|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    232|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 231]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    231|  size_t pos = 0;
  135|    535|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 483, False: 52]
  ------------------
  136|    483|    simd16x32<uint16_t> input_vec(
  137|    483|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    483|    if constexpr (!match_system(big_endian)) {
  139|    483|      input_vec.swap_bytes();
  140|    483|    }
  141|    483|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    483|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 179, False: 304]
  ------------------
  143|       |      // Found a match, return the first one
  144|    179|      int index = trailing_zeroes(~matches) / 2;
  145|    179|      return result(error_code::TOO_LARGE, pos + index);
  146|    179|    }
  147|    483|  }
  148|       |
  149|       |  // Scalar tail
  150|    155|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 134, False: 21]
  ------------------
  151|       |
  152|    134|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    134|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 31, False: 103]
  ------------------
  154|     31|      return result(error_code::TOO_LARGE, pos);
  155|     31|    }
  156|    103|    pos++;
  157|    103|  }
  158|     21|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.67k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.67k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.67k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.67k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.67k|  const char16_t *start = input;
   55|  1.67k|  const char16_t *end = input + size;
   56|       |
   57|  1.67k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.67k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.67k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.67k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   727k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 726k, False: 1.42k]
  ------------------
   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|   726k|    auto in0 = simd16<uint16_t>(input);
   67|   726k|    auto in1 =
   68|   726k|        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|   726k|    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|   726k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   726k|    const uint16_t surrogates_bitmask =
   77|   726k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   726k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 713k, False: 12.6k]
  ------------------
   79|   713k|      input += 16;
   80|   713k|    } 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|  12.6k|      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|  12.6k|      const auto vH = (in & v_fc) == v_dc;
   93|  12.6k|      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|  12.6k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  12.6k|      const uint16_t a = static_cast<uint16_t>(
  100|  12.6k|          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|  12.6k|      const uint16_t b = static_cast<uint16_t>(
  104|  12.6k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  12.6k|      const uint16_t c = static_cast<uint16_t>(
  107|  12.6k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  12.6k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 10.7k, False: 1.90k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  10.7k|        input += 16;
  113|  10.7k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.65k, False: 250]
  ------------------
  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.65k|        input += 15;
  119|  1.65k|      } else {
  120|    250|        return result(error_code::SURROGATE, input - start);
  121|    250|      }
  122|  12.6k|    }
  123|   726k|  }
  124|       |
  125|  1.42k|  return result(error_code::SUCCESS, input - start);
  126|  1.67k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|  1.28k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.28k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.28k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.28k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.28k|  const char16_t *start = input;
   55|  1.28k|  const char16_t *end = input + size;
   56|       |
   57|  1.28k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.28k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.28k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.28k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   522k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 521k, False: 1.09k]
  ------------------
   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|   521k|    auto in0 = simd16<uint16_t>(input);
   67|   521k|    auto in1 =
   68|   521k|        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|   521k|    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|   521k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   521k|    const uint16_t surrogates_bitmask =
   77|   521k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   521k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 508k, False: 12.8k]
  ------------------
   79|   508k|      input += 16;
   80|   508k|    } 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|  12.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|  12.8k|      const auto vH = (in & v_fc) == v_dc;
   93|  12.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|  12.8k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  12.8k|      const uint16_t a = static_cast<uint16_t>(
  100|  12.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|  12.8k|      const uint16_t b = static_cast<uint16_t>(
  104|  12.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|  12.8k|      const uint16_t c = static_cast<uint16_t>(
  107|  12.8k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  12.8k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 10.7k, False: 2.04k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  10.7k|        input += 16;
  113|  10.7k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.85k, False: 187]
  ------------------
  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.85k|        input += 15;
  119|  1.85k|      } else {
  120|    187|        return result(error_code::SURROGATE, input - start);
  121|    187|      }
  122|  12.8k|    }
  123|   521k|  }
  124|       |
  125|  1.09k|  return result(error_code::SUCCESS, input - start);
  126|  1.28k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    232|                                                 size_t size) {
  131|    232|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    232|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 231]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    231|  size_t pos = 0;
  135|    537|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 483, False: 54]
  ------------------
  136|    483|    simd16x32<uint16_t> input_vec(
  137|    483|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    483|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    483|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 177, False: 306]
  ------------------
  143|       |      // Found a match, return the first one
  144|    177|      int index = trailing_zeroes(~matches) / 2;
  145|    177|      return result(error_code::TOO_LARGE, pos + index);
  146|    177|    }
  147|    483|  }
  148|       |
  149|       |  // Scalar tail
  150|    143|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 121, False: 22]
  ------------------
  151|       |
  152|    121|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    121|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 32, False: 89]
  ------------------
  154|     32|      return result(error_code::TOO_LARGE, pos);
  155|     32|    }
  156|     89|    pos++;
  157|     89|  }
  158|     22|  return result(error_code::SUCCESS, size);
  159|     54|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    232|                                                 size_t size) {
  131|    232|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    232|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 231]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    231|  size_t pos = 0;
  135|    535|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 483, False: 52]
  ------------------
  136|    483|    simd16x32<uint16_t> input_vec(
  137|    483|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    483|    if constexpr (!match_system(big_endian)) {
  139|    483|      input_vec.swap_bytes();
  140|    483|    }
  141|    483|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    483|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 179, False: 304]
  ------------------
  143|       |      // Found a match, return the first one
  144|    179|      int index = trailing_zeroes(~matches) / 2;
  145|    179|      return result(error_code::TOO_LARGE, pos + index);
  146|    179|    }
  147|    483|  }
  148|       |
  149|       |  // Scalar tail
  150|    155|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 134, False: 21]
  ------------------
  151|       |
  152|    134|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    134|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 31, False: 103]
  ------------------
  154|     31|      return result(error_code::TOO_LARGE, pos);
  155|     31|    }
  156|    103|    pos++;
  157|    103|  }
  158|     21|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.04k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.04k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.04k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.04k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.04k|  const char16_t *start = input;
   55|  1.04k|  const char16_t *end = input + size;
   56|       |
   57|  1.04k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.04k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.04k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.04k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   654k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 653k, False: 951]
  ------------------
   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|   653k|    auto in0 = simd16<uint16_t>(input);
   67|   653k|    auto in1 =
   68|   653k|        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|   653k|    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|   653k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   653k|    const uint16_t surrogates_bitmask =
   77|   653k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   653k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 640k, False: 12.2k]
  ------------------
   79|   640k|      input += 16;
   80|   640k|    } 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|  12.2k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  12.2k|      const auto vH = (in & v_fc) == v_dc;
   93|  12.2k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  12.2k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  12.2k|      const uint16_t a = static_cast<uint16_t>(
  100|  12.2k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  12.2k|      const uint16_t b = static_cast<uint16_t>(
  104|  12.2k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  12.2k|      const uint16_t c = static_cast<uint16_t>(
  107|  12.2k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  12.2k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 10.5k, False: 1.64k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  10.5k|        input += 16;
  113|  10.5k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.55k, False: 91]
  ------------------
  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.55k|        input += 15;
  119|  1.55k|      } else {
  120|     91|        return result(error_code::SURROGATE, input - start);
  121|     91|      }
  122|  12.2k|    }
  123|   653k|  }
  124|       |
  125|    951|  return result(error_code::SUCCESS, input - start);
  126|  1.04k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|    653|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|    653|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    653|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 653]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|    653|  const char16_t *start = input;
   55|    653|  const char16_t *end = input + size;
   56|       |
   57|    653|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|    653|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|    653|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|    653|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   447k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 446k, False: 653]
  ------------------
   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|   446k|    auto in0 = simd16<uint16_t>(input);
   67|   446k|    auto in1 =
   68|   446k|        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|   446k|    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|   446k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   446k|    const uint16_t surrogates_bitmask =
   77|   446k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   446k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 434k, False: 12.3k]
  ------------------
   79|   434k|      input += 16;
   80|   434k|    } 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|  12.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|  12.3k|      const auto vH = (in & v_fc) == v_dc;
   93|  12.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|  12.3k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  12.3k|      const uint16_t a = static_cast<uint16_t>(
  100|  12.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|  12.3k|      const uint16_t b = static_cast<uint16_t>(
  104|  12.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|  12.3k|      const uint16_t c = static_cast<uint16_t>(
  107|  12.3k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  12.3k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 10.6k, False: 1.71k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  10.6k|        input += 16;
  113|  10.6k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.71k, 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.71k|        input += 15;
  119|  1.71k|      } else {
  120|      0|        return result(error_code::SURROGATE, input - start);
  121|      0|      }
  122|  12.3k|    }
  123|   446k|  }
  124|       |
  125|    653|  return result(error_code::SUCCESS, input - start);
  126|    653|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

