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

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

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

_ZNK7simdutf14implementation4nameEv:
 5106|      4|  virtual std::string_view name() const noexcept { return _name; }
_ZNK7simdutf14implementation25required_instruction_setsEv:
 5157|     10|  virtual uint32_t required_instruction_sets() const {
 5158|     10|    return _required_instruction_sets;
 5159|     10|  }
_ZN7simdutf14implementationC2EPKcS2_j:
 7043|      5|      : _name(name), _description(description),
 7044|      5|        _required_instruction_sets(required_instruction_sets) {}
_ZN7simdutf8internal29available_implementation_listC2Ev:
 7075|      1|  simdutf_really_inline available_implementation_list() {}
simdutf.cpp:_ZN7simdutf6detail12_GLOBAL__N_13minEmm:
   59|    526|constexpr std::size_t min(std::size_t a, std::size_t b) {
   60|    526|  return a < b ? a : b;
  ------------------
  |  Branch (60:10): [True: 152, False: 374]
  ------------------
   61|    526|}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEaSEPS3_:
 7146|      1|  atomic_ptr &operator=(T *_ptr) {
 7147|      1|    ptr = _ptr;
 7148|      1|    return *this;
 7149|      1|  }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEcvPS3_Ev:
 7143|      1|  operator T *() { return ptr.load(); }
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEC2EPS3_:
 7123|      1|  atomic_ptr(T *_ptr) : ptr{_ptr} {}
_ZN7simdutf8internal10atomic_ptrIKNS_14implementationEEptEv:
 7145|    526|  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|    190|                                                      size_t len) noexcept {
   17|    190|  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|    190|  {
   25|   144k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (25:12): [True: 144k, False: 79]
  ------------------
   26|   144k|      uint64_t v1;
   27|   144k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   28|   144k|      uint64_t v2;
   29|   144k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   30|   144k|      uint64_t v{v1 | v2};
   31|   144k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (31:11): [True: 111, False: 144k]
  ------------------
   32|    111|        return false;
   33|    111|      }
   34|   144k|    }
   35|    190|  }
   36|       |
   37|       |  // process the tail byte-by-byte
   38|    408|  for (; pos < len; pos++) {
  ------------------
  |  Branch (38:10): [True: 359, False: 49]
  ------------------
   39|    359|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (39:9): [True: 30, False: 329]
  ------------------
   40|     30|      return false;
   41|     30|    }
   42|    359|  }
   43|     49|  return true;
   44|     79|}
simdutf.cpp:_ZN7simdutf6scalar12_GLOBAL__N_15ascii20validate_with_errorsIPKcQsr7simdutf6detailE22indexes_into_byte_likeIT_EEENS_6resultES6_m:
   50|    762|validate_with_errors(InputPtr data, size_t len) noexcept {
   51|    762|  size_t pos = 0;
   52|       |#if SIMDUTF_CPLUSPLUS23
   53|       |  // avoid memcpy during constant evaluation
   54|       |  if !consteval
   55|       |#endif
   56|    762|  {
   57|       |    // process in blocks of 16 bytes when possible
   58|   168k|    for (; pos + 16 <= len; pos += 16) {
  ------------------
  |  Branch (58:12): [True: 168k, False: 156]
  ------------------
   59|   168k|      uint64_t v1;
   60|   168k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
   61|   168k|      uint64_t v2;
   62|   168k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
   63|   168k|      uint64_t v{v1 | v2};
   64|   168k|      if ((v & 0x8080808080808080) != 0) {
  ------------------
  |  Branch (64:11): [True: 606, False: 167k]
  ------------------
   65|  3.28k|        for (; pos < len; pos++) {
  ------------------
  |  Branch (65:16): [True: 3.28k, False: 0]
  ------------------
   66|  3.28k|          if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (66:15): [True: 606, False: 2.68k]
  ------------------
   67|    606|            return result(error_code::TOO_LARGE, pos);
   68|    606|          }
   69|  3.28k|        }
   70|    606|      }
   71|   168k|    }
   72|    762|  }
   73|       |
   74|       |  // process the tail byte-by-byte
   75|    544|  for (; pos < len; pos++) {
  ------------------
  |  Branch (75:10): [True: 514, False: 30]
  ------------------
   76|    514|    if (static_cast<std::uint8_t>(data[pos]) >= 0b10000000) {
  ------------------
  |  Branch (76:9): [True: 126, False: 388]
  ------------------
   77|    126|      return result(error_code::TOO_LARGE, pos);
   78|    126|    }
   79|    514|  }
   80|     30|  return result(error_code::SUCCESS, pos);
   81|    156|}

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

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

_ZN7simdutf6scalar5utf1623change_endianness_utf16EPKDsmPDs:
  119|    375|change_endianness_utf16(const char16_t *input, size_t size, char16_t *output) {
  120|  2.27M|  for (size_t i = 0; i < size; i++) {
  ------------------
  |  Branch (120:22): [True: 2.27M, False: 375]
  ------------------
  121|  2.27M|    *output++ = char16_t(input[i] >> 8 | input[i] << 8);
  122|  2.27M|  }
  123|    375|}
_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|     46|trim_partial_utf16(const char16_t *input, size_t length) {
  128|     46|  if (length == 0) {
  ------------------
  |  Branch (128:7): [True: 1, False: 45]
  ------------------
  129|      1|    return 0;
  130|      1|  }
  131|     45|  uint16_t last_word = uint16_t(input[length - 1]);
  132|     45|  last_word = scalar::utf16::swap_if_needed<big_endian>(last_word);
  133|     45|  length -= ((last_word & 0xFC00) == 0xD800);
  134|     45|  return length;
  135|     46|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE0EEEbPKDsm:
   10|    230|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  15.3k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 15.3k, False: 21]
  ------------------
   12|  15.3k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  15.3k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 209, False: 15.1k]
  ------------------
   14|    209|      return false;
   15|    209|    }
   16|  15.3k|  }
   17|     21|  return true;
   18|    230|}
_ZN7simdutf6scalar5utf1617validate_as_asciiILNS_10endiannessE1EEEbPKDsm:
   10|    230|validate_as_ascii(const char16_t *data, size_t len) noexcept {
   11|  15.8k|  for (size_t pos = 0; pos < len; pos++) {
  ------------------
  |  Branch (11:24): [True: 15.8k, False: 26]
  ------------------
   12|  15.8k|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   13|  15.8k|    if (word >= 0x80) {
  ------------------
  |  Branch (13:9): [True: 204, False: 15.6k]
  ------------------
   14|    204|      return false;
   15|    204|    }
   16|  15.8k|  }
   17|     26|  return true;
   18|    230|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE0EEEbPKDsm:
   22|  4.19k|validate(const char16_t *data, size_t len) noexcept {
   23|  4.19k|  uint64_t pos = 0;
   24|  16.1M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 16.1M, False: 2.95k]
  ------------------
   25|  16.1M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  16.1M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 23.1k, False: 16.1M]
  ------------------
   27|  23.1k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 242, False: 22.9k]
  ------------------
   28|    242|        return false;
   29|    242|      }
   30|  22.9k|      char16_t diff = char16_t(word - 0xD800);
   31|  22.9k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 480, False: 22.4k]
  ------------------
   32|    480|        return false;
   33|    480|      }
   34|  22.4k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [Folded, False: 22.4k]
  ------------------
   35|  22.4k|                               ? u16_swap_bytes(data[pos + 1])
   36|  22.4k|                               : data[pos + 1];
   37|  22.4k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  22.4k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 514, False: 21.9k]
  ------------------
   39|    514|        return false;
   40|    514|      }
   41|  21.9k|      pos += 2;
   42|  16.1M|    } else {
   43|  16.1M|      pos++;
   44|  16.1M|    }
   45|  16.1M|  }
   46|  2.95k|  return true;
   47|  4.19k|}
_ZN7simdutf6scalar5utf168validateILNS_10endiannessE1EEEbPKDsm:
   22|  2.75k|validate(const char16_t *data, size_t len) noexcept {
   23|  2.75k|  uint64_t pos = 0;
   24|  8.11M|  while (pos < len) {
  ------------------
  |  Branch (24:10): [True: 8.10M, False: 2.45k]
  ------------------
   25|  8.10M|    char16_t word = scalar::utf16::swap_if_needed<big_endian>(data[pos]);
   26|  8.10M|    if ((word & 0xF800) == 0xD800) {
  ------------------
  |  Branch (26:9): [True: 20.0k, False: 8.08M]
  ------------------
   27|  20.0k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (27:11): [True: 46, False: 20.0k]
  ------------------
   28|     46|        return false;
   29|     46|      }
   30|  20.0k|      char16_t diff = char16_t(word - 0xD800);
   31|  20.0k|      if (diff > 0x3FF) {
  ------------------
  |  Branch (31:11): [True: 99, False: 19.9k]
  ------------------
   32|     99|        return false;
   33|     99|      }
   34|  19.9k|      char16_t next_word = !match_system(big_endian)
  ------------------
  |  Branch (34:28): [True: 19.9k, Folded]
  ------------------
   35|  19.9k|                               ? u16_swap_bytes(data[pos + 1])
   36|  19.9k|                               : data[pos + 1];
   37|  19.9k|      char16_t diff2 = char16_t(next_word - 0xDC00);
   38|  19.9k|      if (diff2 > 0x3FF) {
  ------------------
  |  Branch (38:11): [True: 157, False: 19.7k]
  ------------------
   39|    157|        return false;
   40|    157|      }
   41|  19.7k|      pos += 2;
   42|  8.08M|    } else {
   43|  8.08M|      pos++;
   44|  8.08M|    }
   45|  8.10M|  }
   46|  2.45k|  return true;
   47|  2.75k|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE0EEEvPKDsmPDs:
  190|  1.02k|                                              char16_t *output) {
  191|  1.02k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.02k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.02k|  size_t i = 0;
  194|  8.08M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.08M, False: 1.02k]
  ------------------
  195|  8.08M|    char16_t c = input[i];
  196|  8.08M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.08M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.08M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 32.3k, False: 8.05M]
  |  Branch (198:32): [True: 13.0k, False: 19.3k]
  ------------------
  199|  13.0k|      output[i - 1] = replacement;
  200|  13.0k|    }
  201|       |
  202|  8.08M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.05M, False: 32.3k]
  |  Branch (202:33): [True: 423k, False: 7.63M]
  ------------------
  203|   423k|      output[i] = replacement;
  204|  7.66M|    } else {
  205|  7.66M|      output[i] = input[i];
  206|  7.66M|    }
  207|  8.08M|    high_surrogate_prev = high_surrogate;
  208|  8.08M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.02k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 137, False: 892]
  ------------------
  212|    137|    output[i - 1] = replacement;
  213|    137|  }
  214|  1.02k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE0EEEbDs:
  137|  8.08M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.08M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.08M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 669k, False: 7.41M]
  |  Branch (139:26): [True: 32.6k, False: 637k]
  ------------------
  140|  8.08M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE0EEEbDs:
  142|  8.08M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.08M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.08M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 637k, False: 7.45M]
  |  Branch (144:26): [True: 442k, False: 194k]
  ------------------
  145|  8.08M|}
_ZN7simdutf6scalar5utf1620to_well_formed_utf16ILNS_10endiannessE1EEEvPKDsmPDs:
  190|  1.02k|                                              char16_t *output) {
  191|  1.02k|  const char16_t replacement = utf16::replacement<big_endian>();
  192|  1.02k|  bool high_surrogate_prev = false, high_surrogate, low_surrogate;
  193|  1.02k|  size_t i = 0;
  194|  8.08M|  for (; i < len; i++) {
  ------------------
  |  Branch (194:10): [True: 8.08M, False: 1.02k]
  ------------------
  195|  8.08M|    char16_t c = input[i];
  196|  8.08M|    high_surrogate = is_high_surrogate<big_endian>(c);
  197|  8.08M|    low_surrogate = is_low_surrogate<big_endian>(c);
  198|  8.08M|    if (high_surrogate_prev && !low_surrogate) {
  ------------------
  |  Branch (198:9): [True: 31.5k, False: 8.05M]
  |  Branch (198:32): [True: 13.0k, False: 18.5k]
  ------------------
  199|  13.0k|      output[i - 1] = replacement;
  200|  13.0k|    }
  201|       |
  202|  8.08M|    if (!high_surrogate_prev && low_surrogate) {
  ------------------
  |  Branch (202:9): [True: 8.05M, False: 31.5k]
  |  Branch (202:33): [True: 423k, False: 7.63M]
  ------------------
  203|   423k|      output[i] = replacement;
  204|  7.66M|    } else {
  205|  7.66M|      output[i] = input[i];
  206|  7.66M|    }
  207|  8.08M|    high_surrogate_prev = high_surrogate;
  208|  8.08M|  }
  209|       |
  210|       |  /* string may not end with high surrogate */
  211|  1.02k|  if (high_surrogate_prev) {
  ------------------
  |  Branch (211:7): [True: 129, False: 900]
  ------------------
  212|    129|    output[i - 1] = replacement;
  213|    129|  }
  214|  1.02k|}
_ZN7simdutf6scalar5utf1617is_high_surrogateILNS_10endiannessE1EEEbDs:
  137|  8.08M|template <endianness big_endian> constexpr bool is_high_surrogate(char16_t c) {
  138|  8.08M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  139|  8.08M|  return (0xd800 <= c && c <= 0xdbff);
  ------------------
  |  Branch (139:11): [True: 661k, False: 7.42M]
  |  Branch (139:26): [True: 31.8k, False: 629k]
  ------------------
  140|  8.08M|}
_ZN7simdutf6scalar5utf1616is_low_surrogateILNS_10endiannessE1EEEbDs:
  142|  8.08M|template <endianness big_endian> constexpr bool is_low_surrogate(char16_t c) {
  143|  8.08M|  c = scalar::utf16::swap_if_needed<big_endian>(c);
  144|  8.08M|  return (0xdc00 <= c && c <= 0xdfff);
  ------------------
  |  Branch (144:11): [True: 629k, False: 7.45M]
  |  Branch (144:26): [True: 442k, False: 187k]
  ------------------
  145|  8.08M|}

_ZN7simdutf6scalar5utf328validateEPKDim:
   25|    804|                                                        size_t len) noexcept {
   26|    804|  return validate(reinterpret_cast<const uint32_t *>(buf), len);
   27|    804|}
_ZN7simdutf6scalar5utf328validateIPKjQsr7simdutf6detailE19indexes_into_uint32IT_EEEbS5_m:
   13|    804|                                                      size_t len) noexcept {
   14|    804|  uint64_t pos = 0;
   15|  23.5k|  for (; pos < len; pos++) {
  ------------------
  |  Branch (15:10): [True: 23.3k, False: 154]
  ------------------
   16|  23.3k|    uint32_t word = data[pos];
   17|  23.3k|    if (word > 0x10FFFF || (word >= 0xD800 && word <= 0xDFFF)) {
  ------------------
  |  Branch (17:9): [True: 565, False: 22.7k]
  |  Branch (17:29): [True: 842, False: 21.9k]
  |  Branch (17:47): [True: 85, False: 757]
  ------------------
   18|    650|      return false;
   19|    650|    }
   20|  23.3k|  }
   21|    154|  return true;
   22|    804|}

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

_ZN7simdutf3BOM9check_bomEPKhm:
   24|  4.06k|encoding_type check_bom(const uint8_t *byte, size_t length) {
   25|  4.06k|  if (length >= 2 && byte[0] == 0xff and byte[1] == 0xfe) {
  ------------------
  |  Branch (25:7): [True: 4.00k, False: 60]
  |  Branch (25:22): [True: 525, False: 3.47k]
  |  Branch (25:42): [True: 225, False: 300]
  ------------------
   26|    225|    if (length >= 4 && byte[2] == 0x00 and byte[3] == 0x0) {
  ------------------
  |  Branch (26:9): [True: 216, False: 9]
  |  Branch (26:24): [True: 84, False: 132]
  |  Branch (26:44): [True: 15, False: 69]
  ------------------
   27|     15|      return encoding_type::UTF32_LE;
   28|    210|    } else {
   29|    210|      return encoding_type::UTF16_LE;
   30|    210|    }
   31|  3.83k|  } else if (length >= 2 && byte[0] == 0xfe and byte[1] == 0xff) {
  ------------------
  |  Branch (31:14): [True: 3.77k, False: 60]
  |  Branch (31:29): [True: 105, False: 3.67k]
  |  Branch (31:49): [True: 6, False: 99]
  ------------------
   32|      6|    return encoding_type::UTF16_BE;
   33|  3.83k|  } else if (length >= 4 && byte[0] == 0x00 and byte[1] == 0x00 and
  ------------------
  |  Branch (33:14): [True: 3.21k, False: 612]
  |  Branch (33:29): [True: 990, False: 2.22k]
  |  Branch (33:49): [True: 636, False: 354]
  ------------------
   34|    636|             byte[2] == 0xfe and byte[3] == 0xff) {
  ------------------
  |  Branch (34:14): [True: 66, False: 570]
  |  Branch (34:34): [True: 6, False: 60]
  ------------------
   35|      6|    return encoding_type::UTF32_BE;
   36|  3.82k|  } else if (length >= 3 && byte[0] == 0xef and byte[1] == 0xbb and
  ------------------
  |  Branch (36:14): [True: 3.50k, False: 321]
  |  Branch (36:29): [True: 288, False: 3.21k]
  |  Branch (36:49): [True: 120, False: 168]
  ------------------
   37|    120|             byte[2] == 0xbf) {
  ------------------
  |  Branch (37:14): [True: 6, False: 114]
  ------------------
   38|      6|    return encoding_type::UTF8;
   39|      6|  }
   40|  3.81k|  return encoding_type::unspecified;
   41|  4.06k|}
_ZN7simdutf3BOM9check_bomEPKcm:
   43|  4.06k|encoding_type check_bom(const char *byte, size_t length) {
   44|  4.06k|  return check_bom(reinterpret_cast<const uint8_t *>(byte), length);
   45|  4.06k|}

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

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

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

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

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

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

simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 229]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    229|  size_t pos = 0;
  135|    661|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 609, False: 52]
  ------------------
  136|    609|    simd16x32<uint16_t> input_vec(
  137|    609|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    609|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    609|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 177, False: 432]
  ------------------
  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|    609|  }
  148|       |
  149|       |  // Scalar tail
  150|    138|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 118, False: 20]
  ------------------
  151|       |
  152|    118|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    118|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 32, False: 86]
  ------------------
  154|     32|      return result(error_code::TOO_LARGE, pos);
  155|     32|    }
  156|     86|    pos++;
  157|     86|  }
  158|     20|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 229]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    229|  size_t pos = 0;
  135|    675|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 620, False: 55]
  ------------------
  136|    620|    simd16x32<uint16_t> input_vec(
  137|    620|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    620|    if constexpr (!match_system(big_endian)) {
  139|    620|      input_vec.swap_bytes();
  140|    620|    }
  141|    620|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    620|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 174, False: 446]
  ------------------
  143|       |      // Found a match, return the first one
  144|    174|      int index = trailing_zeroes(~matches) / 2;
  145|    174|      return result(error_code::TOO_LARGE, pos + index);
  146|    174|    }
  147|    620|  }
  148|       |
  149|       |  // Scalar tail
  150|    157|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 132, False: 25]
  ------------------
  151|       |
  152|    132|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    132|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 102]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    102|    pos++;
  157|    102|  }
  158|     25|  return result(error_code::SUCCESS, size);
  159|     55|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.87k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.87k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.87k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.87k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.87k|  const char16_t *start = input;
   55|  1.87k|  const char16_t *end = input + size;
   56|       |
   57|  1.87k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.87k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.87k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.87k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   887k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 885k, False: 1.61k]
  ------------------
   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|   885k|    auto in0 = simd16<uint16_t>(input);
   67|   885k|    auto in1 =
   68|   885k|        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|   885k|    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|   885k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   885k|    const uint16_t surrogates_bitmask =
   77|   885k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   885k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 874k, False: 11.0k]
  ------------------
   79|   874k|      input += 16;
   80|   874k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  11.0k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  11.0k|      const auto vH = (in & v_fc) == v_dc;
   93|  11.0k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  11.0k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  11.0k|      const uint16_t a = static_cast<uint16_t>(
  100|  11.0k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  11.0k|      const uint16_t b = static_cast<uint16_t>(
  104|  11.0k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  11.0k|      const uint16_t c = static_cast<uint16_t>(
  107|  11.0k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  11.0k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 9.08k, False: 2.01k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  9.08k|        input += 16;
  113|  9.08k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.75k, False: 256]
  ------------------
  114|       |        // The 15 lower code units of the input register contains valid UTF-16.
  115|       |        // The 15th word may be either a low or high surrogate. It the next
  116|       |        // iteration we 1) check if the low surrogate is followed by a high
  117|       |        // one, 2) reject sole high surrogate.
  118|  1.75k|        input += 15;
  119|  1.75k|      } else {
  120|    256|        return result(error_code::SURROGATE, input - start);
  121|    256|      }
  122|  11.0k|    }
  123|   885k|  }
  124|       |
  125|  1.61k|  return result(error_code::SUCCESS, input - start);
  126|  1.87k|}
simdutf.cpp:_ZN7simdutf7haswell12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|  1.46k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.46k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.46k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.46k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.46k|  const char16_t *start = input;
   55|  1.46k|  const char16_t *end = input + size;
   56|       |
   57|  1.46k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.46k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.46k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.46k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   584k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 583k, False: 1.26k]
  ------------------
   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|   583k|    auto in0 = simd16<uint16_t>(input);
   67|   583k|    auto in1 =
   68|   583k|        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|   583k|    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|   583k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   583k|    const uint16_t surrogates_bitmask =
   77|   583k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   583k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 572k, False: 10.3k]
  ------------------
   79|   572k|      input += 16;
   80|   572k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  10.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|  10.3k|      const auto vH = (in & v_fc) == v_dc;
   93|  10.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|  10.3k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  10.3k|      const uint16_t a = static_cast<uint16_t>(
  100|  10.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|  10.3k|      const uint16_t b = static_cast<uint16_t>(
  104|  10.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|  10.3k|      const uint16_t c = static_cast<uint16_t>(
  107|  10.3k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  10.3k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 8.46k, False: 1.89k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  8.46k|        input += 16;
  113|  8.46k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.69k, False: 193]
  ------------------
  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.69k|        input += 15;
  119|  1.69k|      } else {
  120|    193|        return result(error_code::SURROGATE, input - start);
  121|    193|      }
  122|  10.3k|    }
  123|   583k|  }
  124|       |
  125|  1.26k|  return result(error_code::SUCCESS, input - start);
  126|  1.46k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 229]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    229|  size_t pos = 0;
  135|    661|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 609, False: 52]
  ------------------
  136|    609|    simd16x32<uint16_t> input_vec(
  137|    609|        reinterpret_cast<const uint16_t *>(input + pos));
  138|       |    if constexpr (!match_system(big_endian)) {
  139|       |      input_vec.swap_bytes();
  140|       |    }
  141|    609|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    609|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 177, False: 432]
  ------------------
  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|    609|  }
  148|       |
  149|       |  // Scalar tail
  150|    138|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 118, False: 20]
  ------------------
  151|       |
  152|    118|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    118|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 32, False: 86]
  ------------------
  154|     32|      return result(error_code::TOO_LARGE, pos);
  155|     32|    }
  156|     86|    pos++;
  157|     86|  }
  158|     20|  return result(error_code::SUCCESS, size);
  159|     52|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1635validate_utf16_as_ascii_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
  130|    230|                                                 size_t size) {
  131|    230|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    230|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 1, False: 229]
  |  |  ------------------
  ------------------
  132|      1|    return result(error_code::SUCCESS, 0);
  133|      1|  }
  134|    229|  size_t pos = 0;
  135|    675|  for (; pos < size / 32 * 32; pos += 32) {
  ------------------
  |  Branch (135:10): [True: 620, False: 55]
  ------------------
  136|    620|    simd16x32<uint16_t> input_vec(
  137|    620|        reinterpret_cast<const uint16_t *>(input + pos));
  138|    620|    if constexpr (!match_system(big_endian)) {
  139|    620|      input_vec.swap_bytes();
  140|    620|    }
  141|    620|    uint64_t matches = input_vec.lteq(uint16_t(0x7f));
  142|    620|    if (~matches) {
  ------------------
  |  Branch (142:9): [True: 174, False: 446]
  ------------------
  143|       |      // Found a match, return the first one
  144|    174|      int index = trailing_zeroes(~matches) / 2;
  145|    174|      return result(error_code::TOO_LARGE, pos + index);
  146|    174|    }
  147|    620|  }
  148|       |
  149|       |  // Scalar tail
  150|    157|  while (pos < size) {
  ------------------
  |  Branch (150:10): [True: 132, False: 25]
  ------------------
  151|       |
  152|    132|    char16_t v = scalar::utf16::swap_if_needed<big_endian>(input[pos]);
  153|    132|    if (v > 0x7F) {
  ------------------
  |  Branch (153:9): [True: 30, False: 102]
  ------------------
  154|     30|      return result(error_code::TOO_LARGE, pos);
  155|     30|    }
  156|    102|    pos++;
  157|    102|  }
  158|     25|  return result(error_code::SUCCESS, size);
  159|     55|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE0EEEKNS_6resultEPKDsm:
   49|  1.15k|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|  1.15k|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|  1.15k|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 1.15k]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|  1.15k|  const char16_t *start = input;
   55|  1.15k|  const char16_t *end = input + size;
   56|       |
   57|  1.15k|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|  1.15k|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|  1.15k|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|  1.15k|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   811k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 810k, False: 1.05k]
  ------------------
   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|   810k|    auto in0 = simd16<uint16_t>(input);
   67|   810k|    auto in1 =
   68|   810k|        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|   810k|    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|   810k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   810k|    const uint16_t surrogates_bitmask =
   77|   810k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   810k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 799k, False: 10.5k]
  ------------------
   79|   799k|      input += 16;
   80|   799k|    } else {
   81|       |      // 2. We have some surrogates that have to be distinguished:
   82|       |      //    - low  surrogates: 0b1101'10xx'yyyy'yyyy (0xD800..0xDBFF)
   83|       |      //    - high surrogates: 0b1101'11xx'yyyy'yyyy (0xDC00..0xDFFF)
   84|       |      //
   85|       |      //    Fact: high surrogate has 11th bit set (3rd bit in the higher byte)
   86|       |
   87|       |      // V - non-surrogate code units
   88|       |      //     V = not surrogates_wordmask
   89|  10.5k|      const uint16_t V = static_cast<uint16_t>(~surrogates_bitmask);
   90|       |
   91|       |      // H - word-mask for high surrogates: the six highest bits are 0b1101'11
   92|  10.5k|      const auto vH = (in & v_fc) == v_dc;
   93|  10.5k|      const uint16_t H = static_cast<uint16_t>(vH.to_bitmask());
   94|       |
   95|       |      // L - word mask for low surrogates
   96|       |      //     L = not H and surrogates_wordmask
   97|  10.5k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  10.5k|      const uint16_t a = static_cast<uint16_t>(
  100|  10.5k|          L & (H >> 1)); // A low surrogate must be followed by high one.
  101|       |                         // (A low surrogate placed in the 7th register's word
  102|       |                         // is an exception we handle.)
  103|  10.5k|      const uint16_t b = static_cast<uint16_t>(
  104|  10.5k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  10.5k|      const uint16_t c = static_cast<uint16_t>(
  107|  10.5k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  10.5k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 8.75k, False: 1.76k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  8.75k|        input += 16;
  113|  8.75k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.65k, False: 103]
  ------------------
  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|    103|        return result(error_code::SURROGATE, input - start);
  121|    103|      }
  122|  10.5k|    }
  123|   810k|  }
  124|       |
  125|  1.05k|  return result(error_code::SUCCESS, input - start);
  126|  1.15k|}
simdutf.cpp:_ZN7simdutf8westmere12_GLOBAL__N_15utf1626validate_utf16_with_errorsILNS_10endiannessE1EEEKNS_6resultEPKDsm:
   49|    743|const result validate_utf16_with_errors(const char16_t *input, size_t size) {
   50|    743|  if (simdutf_unlikely(size == 0)) {
  ------------------
  |  |   93|    743|    #define simdutf_unlikely(x) __builtin_expect(!!(x), 0)
  |  |  ------------------
  |  |  |  Branch (93:33): [True: 0, False: 743]
  |  |  ------------------
  ------------------
   51|      0|    return result(error_code::SUCCESS, 0);
   52|      0|  }
   53|       |
   54|    743|  const char16_t *start = input;
   55|    743|  const char16_t *end = input + size;
   56|       |
   57|    743|  const auto v_d8 = simd8<uint8_t>::splat(0xd8);
   58|    743|  const auto v_f8 = simd8<uint8_t>::splat(0xf8);
   59|    743|  const auto v_fc = simd8<uint8_t>::splat(0xfc);
   60|    743|  const auto v_dc = simd8<uint8_t>::splat(0xdc);
   61|       |
   62|   505k|  while (input + simd16<uint16_t>::SIZE * 2 < end) {
  ------------------
  |  Branch (62:10): [True: 505k, False: 743]
  ------------------
   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|   505k|    auto in0 = simd16<uint16_t>(input);
   67|   505k|    auto in1 =
   68|   505k|        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|   505k|    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|   505k|    const auto surrogates_wordmask = (in & v_f8) == v_d8;
   76|   505k|    const uint16_t surrogates_bitmask =
   77|   505k|        static_cast<uint16_t>(surrogates_wordmask.to_bitmask());
   78|   505k|    if (surrogates_bitmask == 0x0000) {
  ------------------
  |  Branch (78:9): [True: 495k, False: 9.83k]
  ------------------
   79|   495k|      input += 16;
   80|   495k|    } 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|  9.83k|      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|  9.83k|      const auto vH = (in & v_fc) == v_dc;
   93|  9.83k|      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|  9.83k|      const uint16_t L = static_cast<uint16_t>(~H & surrogates_bitmask);
   98|       |
   99|  9.83k|      const uint16_t a = static_cast<uint16_t>(
  100|  9.83k|          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|  9.83k|      const uint16_t b = static_cast<uint16_t>(
  104|  9.83k|          a << 1); // Just mark that the opinput - startite fact is hold,
  105|       |                   // thanks to that we have only two masks for valid case.
  106|  9.83k|      const uint16_t c = static_cast<uint16_t>(
  107|  9.83k|          V | a | b); // Combine all the masks into the final one.
  108|       |
  109|  9.83k|      if (c == 0xffff) {
  ------------------
  |  Branch (109:11): [True: 8.27k, False: 1.56k]
  ------------------
  110|       |        // The whole input register contains valid UTF-16, i.e.,
  111|       |        // either single code units or proper surrogate pairs.
  112|  8.27k|        input += 16;
  113|  8.27k|      } else if (c == 0x7fff) {
  ------------------
  |  Branch (113:18): [True: 1.56k, 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.56k|        input += 15;
  119|  1.56k|      } else {
  120|      0|        return result(error_code::SURROGATE, input - start);
  121|      0|      }
  122|  9.83k|    }
  123|   505k|  }
  124|       |
  125|    743|  return result(error_code::SUCCESS, input - start);
  126|    743|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

