Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : // This file should only be compiled if you're on x86 or x86_64. Additionally,
8 : // you'll need to compile this file with -msse2 if you're using gcc.
9 :
10 : #include <emmintrin.h>
11 : #include "nscore.h"
12 : #include "nsAlgorithm.h"
13 : #include "nsTextFragmentImpl.h"
14 : #include <algorithm>
15 :
16 : namespace mozilla {
17 : namespace SSE2 {
18 :
19 : static inline bool
20 1703 : is_zero (__m128i x)
21 : {
22 : return
23 5109 : _mm_movemask_epi8(_mm_cmpeq_epi8(x, _mm_setzero_si128())) == 0xffff;
24 : }
25 :
26 : int32_t
27 151 : FirstNon8Bit(const char16_t *str, const char16_t *end)
28 : {
29 151 : const uint32_t numUnicharsPerVector = 8;
30 : typedef Non8BitParameters<sizeof(size_t)> p;
31 151 : const size_t mask = p::mask();
32 151 : const uint32_t numUnicharsPerWord = p::numUnicharsPerWord();
33 151 : const int32_t len = end - str;
34 151 : int32_t i = 0;
35 :
36 : // Align ourselves to a 16-byte boundary, as required by _mm_load_si128
37 : // (i.e. MOVDQA).
38 : int32_t alignLen =
39 151 : std::min(len, int32_t(((-NS_PTR_TO_INT32(str)) & 0xf) / sizeof(char16_t)));
40 1217 : for (; i < alignLen; i++) {
41 533 : if (str[i] > 255)
42 0 : return i;
43 : }
44 :
45 : // Check one XMM register (16 bytes) at a time.
46 151 : const int32_t vectWalkEnd = ((len - i) / numUnicharsPerVector) * numUnicharsPerVector;
47 151 : const uint16_t shortMask = 0xff00;
48 151 : __m128i vectmask = _mm_set1_epi16(static_cast<int16_t>(shortMask));
49 3549 : for(; i < vectWalkEnd; i += numUnicharsPerVector) {
50 1703 : const __m128i vect = *reinterpret_cast<const __m128i*>(str + i);
51 1703 : if (!is_zero(_mm_and_si128(vect, vectmask)))
52 4 : return i;
53 : }
54 :
55 : // Check one word at a time.
56 147 : const int32_t wordWalkEnd = ((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
57 153 : for(; i < wordWalkEnd; i += numUnicharsPerWord) {
58 4 : const size_t word = *reinterpret_cast<const size_t*>(str + i);
59 4 : if (word & mask)
60 1 : return i;
61 : }
62 :
63 : // Take care of the remainder one character at a time.
64 1062 : for (; i < len; i++) {
65 461 : if (str[i] > 255) {
66 3 : return i;
67 : }
68 : }
69 :
70 143 : return -1;
71 : }
72 :
73 : } // namespace SSE2
74 : } // namespace mozilla
|