CharacterDataBufferVMX.cpp (3327B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // This file should only be compiled if you're on Power ISA. 6 7 #include <altivec.h> 8 9 #include <algorithm> 10 11 #include "CharacterDataBufferImpl.h" 12 #include "mozilla/Assertions.h" 13 #include "nscore.h" 14 15 namespace mozilla { 16 namespace VMX { 17 18 int32_t FirstNon8Bit(const char16_t* str, const char16_t* end) { 19 const uint32_t numUnicharsPerVector = 8; 20 const uint32_t numCharsPerVector = 16; 21 // Paranoia. If this assertion is wrong, change the vector loop below. 22 MOZ_ASSERT((numCharsPerVector / numUnicharsPerVector) == sizeof(char16_t)); 23 24 typedef Non8BitParameters<sizeof(size_t)> p; 25 const uint32_t alignMask = p::alignMask(); 26 const size_t mask = p::mask(); 27 const uint32_t numUnicharsPerWord = p::numUnicharsPerWord(); 28 29 const uint32_t len = end - str; 30 31 // i shall count the index in unichars; i2 shall count the index in chars. 32 uint32_t i = 0; 33 uint32_t i2 = 0; 34 35 // Align ourselves to a 16-byte boundary, as required by VMX loads. 36 uint32_t alignLen = std::min( 37 len, uint32_t(((-NS_PTR_TO_UINT32(str)) & 0xf) / sizeof(char16_t))); 38 39 if ((len - alignLen) >= numUnicharsPerVector) { 40 for (; i < alignLen; i++) { 41 if (str[i] > 255) return i; 42 } 43 44 // Construct a vector of shorts. 45 #if __LITTLE_ENDIAN__ 46 const vector unsigned short gtcompare = 47 reinterpret_cast<vector unsigned short>( 48 vec_mergel(vec_splat_s8(-1), vec_splat_s8(0))); 49 #else 50 const vector unsigned short gtcompare = 51 reinterpret_cast<vector unsigned short>( 52 vec_mergel(vec_splat_s8(0), vec_splat_s8(-1))); 53 #endif 54 const uint32_t vectWalkEnd = 55 ((len - i) / numUnicharsPerVector) * numUnicharsPerVector; 56 i2 = i * sizeof(char16_t); 57 58 while (1) { 59 vector unsigned short vect; 60 61 // Check one VMX register (8 unichars) at a time. The vec_any_gt 62 // intrinsic does exactly what we want. This loop is manually unrolled; 63 // it yields notable performance improvements this way. 64 #define CheckForASCII \ 65 vect = vec_ld(i2, reinterpret_cast<const unsigned short*>(str)); \ 66 if (vec_any_gt(vect, gtcompare)) return i; \ 67 i += numUnicharsPerVector; \ 68 if (!(i < vectWalkEnd)) break; \ 69 i2 += numCharsPerVector; 70 71 CheckForASCII CheckForASCII 72 73 #undef CheckForASCII 74 } 75 } else { 76 // Align ourselves to a word boundary. 77 alignLen = std::min(len, uint32_t(((-NS_PTR_TO_UINT32(str)) & alignMask) / 78 sizeof(char16_t))); 79 for (; i < alignLen; i++) { 80 if (str[i] > 255) return i; 81 } 82 } 83 84 // Check one word at a time. 85 const uint32_t wordWalkEnd = 86 ((len - i) / numUnicharsPerWord) * numUnicharsPerWord; 87 for (; i < wordWalkEnd; i += numUnicharsPerWord) { 88 const size_t word = *reinterpret_cast<const size_t*>(str + i); 89 if (word & mask) return i; 90 } 91 92 // Take care of the remainder one character at a time. 93 for (; i < len; i++) { 94 if (str[i] > 255) { 95 return i; 96 } 97 } 98 99 return -1; 100 } 101 102 } // namespace VMX 103 } // namespace mozilla