| /* |
| * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. |
| * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #ifndef ASCIIFastPath_h |
| #define ASCIIFastPath_h |
| |
| #include "platform/wtf/Alignment.h" |
| #include "platform/wtf/CPU.h" |
| #include "platform/wtf/StdLibExtras.h" |
| #include "platform/wtf/text/Unicode.h" |
| #include <stdint.h> |
| |
| #if OS(MACOSX) && (CPU(X86) || CPU(X86_64)) |
| #include <emmintrin.h> |
| #endif |
| |
| namespace WTF { |
| |
| // Assuming that a pointer is the size of a "machine word", then |
| // uintptr_t is an integer type that is also a machine word. |
| typedef uintptr_t MachineWord; |
| const uintptr_t kMachineWordAlignmentMask = sizeof(MachineWord) - 1; |
| |
| inline bool IsAlignedToMachineWord(const void* pointer) { |
| return !(reinterpret_cast<uintptr_t>(pointer) & kMachineWordAlignmentMask); |
| } |
| |
| template <typename T> |
| inline T* AlignToMachineWord(T* pointer) { |
| return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(pointer) & |
| ~kMachineWordAlignmentMask); |
| } |
| |
| template <size_t size, typename CharacterType> |
| struct NonASCIIMask; |
| template <> |
| struct NonASCIIMask<4, UChar> { |
| static inline uint32_t Value() { return 0xFF80FF80U; } |
| }; |
| template <> |
| struct NonASCIIMask<4, LChar> { |
| static inline uint32_t Value() { return 0x80808080U; } |
| }; |
| template <> |
| struct NonASCIIMask<8, UChar> { |
| static inline uint64_t Value() { return 0xFF80FF80FF80FF80ULL; } |
| }; |
| template <> |
| struct NonASCIIMask<8, LChar> { |
| static inline uint64_t Value() { return 0x8080808080808080ULL; } |
| }; |
| |
| template <typename CharacterType> |
| inline bool IsAllASCII(MachineWord word) { |
| return !(word & NonASCIIMask<sizeof(MachineWord), CharacterType>::Value()); |
| } |
| |
| // Note: This function assume the input is likely all ASCII, and |
| // does not leave early if it is not the case. |
| template <typename CharacterType> |
| inline bool CharactersAreAllASCII(const CharacterType* characters, |
| size_t length) { |
| DCHECK_GT(length, 0u); |
| MachineWord all_char_bits = 0; |
| const CharacterType* end = characters + length; |
| |
| // Prologue: align the input. |
| while (!IsAlignedToMachineWord(characters) && characters != end) { |
| all_char_bits |= *characters; |
| ++characters; |
| } |
| |
| // Compare the values of CPU word size. |
| const CharacterType* word_end = AlignToMachineWord(end); |
| const size_t kLoopIncrement = sizeof(MachineWord) / sizeof(CharacterType); |
| while (characters < word_end) { |
| all_char_bits |= *(reinterpret_cast_ptr<const MachineWord*>(characters)); |
| characters += kLoopIncrement; |
| } |
| |
| // Process the remaining bytes. |
| while (characters != end) { |
| all_char_bits |= *characters; |
| ++characters; |
| } |
| |
| MachineWord non_ascii_bit_mask = |
| NonASCIIMask<sizeof(MachineWord), CharacterType>::Value(); |
| return !(all_char_bits & non_ascii_bit_mask); |
| } |
| |
| inline void CopyLCharsFromUCharSource(LChar* destination, |
| const UChar* source, |
| size_t length) { |
| #if OS(MACOSX) && (CPU(X86) || CPU(X86_64)) |
| const uintptr_t kMemoryAccessSize = |
| 16; // Memory accesses on 16 byte (128 bit) alignment |
| const uintptr_t kMemoryAccessMask = kMemoryAccessSize - 1; |
| |
| size_t i = 0; |
| for (; i < length && !IsAlignedTo<kMemoryAccessMask>(&source[i]); ++i) { |
| DCHECK(!(source[i] & 0xff00)); |
| destination[i] = static_cast<LChar>(source[i]); |
| } |
| |
| const uintptr_t kSourceLoadSize = |
| 32; // Process 32 bytes (16 UChars) each iteration |
| const size_t kUcharsPerLoop = kSourceLoadSize / sizeof(UChar); |
| if (length > kUcharsPerLoop) { |
| const size_t end_length = length - kUcharsPerLoop + 1; |
| for (; i < end_length; i += kUcharsPerLoop) { |
| #if DCHECK_IS_ON() |
| for (unsigned check_index = 0; check_index < kUcharsPerLoop; |
| ++check_index) |
| DCHECK(!(source[i + check_index] & 0xff00)); |
| #endif |
| __m128i first8u_chars = |
| _mm_load_si128(reinterpret_cast<const __m128i*>(&source[i])); |
| __m128i second8u_chars = |
| _mm_load_si128(reinterpret_cast<const __m128i*>(&source[i + 8])); |
| __m128i packed_chars = _mm_packus_epi16(first8u_chars, second8u_chars); |
| _mm_storeu_si128(reinterpret_cast<__m128i*>(&destination[i]), |
| packed_chars); |
| } |
| } |
| |
| for (; i < length; ++i) { |
| DCHECK(!(source[i] & 0xff00)); |
| destination[i] = static_cast<LChar>(source[i]); |
| } |
| #elif COMPILER(GCC) && CPU(ARM_NEON) && \ |
| !(CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)) && defined(NDEBUG) |
| const LChar* const end = destination + length; |
| const uintptr_t kMemoryAccessSize = 8; |
| |
| if (length >= (2 * kMemoryAccessSize) - 1) { |
| // Prefix: align dst on 64 bits. |
| const uintptr_t kMemoryAccessMask = kMemoryAccessSize - 1; |
| while (!IsAlignedTo<kMemoryAccessMask>(destination)) |
| *destination++ = static_cast<LChar>(*source++); |
| |
| // Vector interleaved unpack, we only store the lower 8 bits. |
| const uintptr_t length_left = end - destination; |
| const LChar* const simd_end = end - (length_left % kMemoryAccessSize); |
| do { |
| asm("vld2.8 { d0-d1 }, [%[SOURCE]] !\n\t" |
| "vst1.8 { d0 }, [%[DESTINATION],:64] !\n\t" |
| : [SOURCE] "+r"(source), [DESTINATION] "+r"(destination) |
| : |
| : "memory", "d0", "d1"); |
| } while (destination != simd_end); |
| } |
| |
| while (destination != end) |
| *destination++ = static_cast<LChar>(*source++); |
| #else |
| for (size_t i = 0; i < length; ++i) { |
| DCHECK(!(source[i] & 0xff00)); |
| destination[i] = static_cast<LChar>(source[i]); |
| } |
| #endif |
| } |
| |
| } // namespace WTF |
| |
| #endif // ASCIIFastPath_h |