diff --git a/indra/llprimitive/llmaterialid.cpp b/indra/llprimitive/llmaterialid.cpp index f88a607c4f9b167fd73f022166351f2f905e5dbd..6f3b45a5b8e3fc8680d3716a74fd94a5f27a8635 100644 --- a/indra/llprimitive/llmaterialid.cpp +++ b/indra/llprimitive/llmaterialid.cpp @@ -35,11 +35,6 @@ const LLMaterialID LLMaterialID::null; -LLMaterialID::LLMaterialID() -{ - clear(); -} - LLMaterialID::LLMaterialID(const LLSD& pMaterialID) { llassert(pMaterialID.isBinary()); @@ -56,61 +51,11 @@ LLMaterialID::LLMaterialID(const void* pMemory) set(pMemory); } -LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); -} - LLMaterialID::LLMaterialID(const LLUUID& lluid) { set(lluid.mData); } -LLMaterialID::~LLMaterialID() -{ -} - -bool LLMaterialID::operator == (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) == 0); -} - -bool LLMaterialID::operator != (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) != 0); -} - -bool LLMaterialID::operator < (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) < 0); -} - -bool LLMaterialID::operator <= (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) <= 0); -} - -bool LLMaterialID::operator > (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) > 0); -} - -bool LLMaterialID::operator >= (const LLMaterialID& pOtherMaterialID) const -{ - return (compareToOtherMaterialID(pOtherMaterialID) >= 0); -} - -LLMaterialID& LLMaterialID::operator = (const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); - return (*this); -} - -bool LLMaterialID::isNull() const -{ - return (compareToOtherMaterialID(LLMaterialID::null) == 0); -} - const U8* LLMaterialID::get() const { return mID; @@ -161,28 +106,8 @@ std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id) return s; } - void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID) { llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8))); memcpy(mID, &pMaterialID[0], MATERIAL_ID_SIZE * sizeof(U8)); } - -void LLMaterialID::copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID) -{ - memcpy(mID, pOtherMaterialID.get(), MATERIAL_ID_SIZE * sizeof(U8)); -} - -int LLMaterialID::compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const -{ - int retVal = 0; - - for (unsigned int i = 0U; (retVal == 0) && (i < static_cast<unsigned int>(MATERIAL_ID_SIZE / sizeof(U32))); ++i) - { - const U32 *thisValue = reinterpret_cast<const U32*>(&get()[i * sizeof(U32)]); - const U32 *otherValue = reinterpret_cast<const U32*>(&pOtherMaterialID.get()[i * sizeof(U32)]); - retVal = ((*thisValue < *otherValue) ? -1 : ((*thisValue > *otherValue) ? 1 : 0)); - } - - return retVal; -} diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h index ee663f8f99f41c6926102f0cb14bff7220ec098d..3f7a0bb3ed6458f08728d371d615f237febb3adc 100644 --- a/indra/llprimitive/llmaterialid.h +++ b/indra/llprimitive/llmaterialid.h @@ -30,30 +30,126 @@ #define MATERIAL_ID_SIZE 16 #include <string> +#include <immintrin.h> #include "llsd.h" class LLMaterialID { public: - LLMaterialID(); + LLMaterialID() = default; LLMaterialID(const LLSD& pMaterialID); LLMaterialID(const LLSD::Binary& pMaterialID); LLMaterialID(const void* pMemory); - LLMaterialID(const LLMaterialID& pOtherMaterialID); LLMaterialID(const LLUUID& lluid); - ~LLMaterialID(); - bool operator == (const LLMaterialID& pOtherMaterialID) const; - bool operator != (const LLMaterialID& pOtherMaterialID) const; +// BEGIN BOOST +// Contains code from the Boost Library with license below. +/* + * Copyright Andrey Semashev 2013. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + LL_FORCE_INLINE __m128i load_unaligned_si128(const U8* p) const + { +#if defined(AL_AVX) + return _mm_lddqu_si128(reinterpret_cast<const __m128i*>(p)); +#else + return _mm_loadu_si128(reinterpret_cast<const __m128i*>(p)); +#endif + } - bool operator < (const LLMaterialID& pOtherMaterialID) const; - bool operator <= (const LLMaterialID& pOtherMaterialID) const; - bool operator > (const LLMaterialID& pOtherMaterialID) const; - bool operator >= (const LLMaterialID& pOtherMaterialID) const; + bool operator==(const LLMaterialID& rhs) const + { + __m128i mm_left = load_unaligned_si128(mID); + __m128i mm_right = load_unaligned_si128(rhs.mID); - LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID); + __m128i mm_cmp = _mm_cmpeq_epi32(mm_left, mm_right); +#if defined(AL_AVX) + return _mm_test_all_ones(mm_cmp); +#else + return _mm_movemask_epi8(mm_cmp) == 0xFFFF; +#endif + } - bool isNull() const; + bool operator!=(const LLMaterialID& rhs) const + { + return !((*this) == rhs); + } + + bool operator<(const LLMaterialID& rhs) const + { + __m128i mm_left = _mm_lddqu_si128(reinterpret_cast<const __m128i*>(mID)); + __m128i mm_right = _mm_lddqu_si128(reinterpret_cast<const __m128i*>(rhs.mID)); + + // To emulate lexicographical_compare behavior we have to perform two comparisons - the forward and reverse one. + // Then we know which bytes are equivalent and which ones are different, and for those different the comparison results + // will be opposite. Then we'll be able to find the first differing comparison result (for both forward and reverse ways), + // and depending on which way it is for, this will be the result of the operation. There are a few notes to consider: + // + // 1. Due to little endian byte order the first bytes go into the lower part of the xmm registers, + // so the comparison results in the least significant bits will actually be the most signigicant for the final operation result. + // This means we have to determine which of the comparison results have the least significant bit on, and this is achieved with + // the "(x - 1) ^ x" trick. + // 2. Because there is only signed comparison in SSE/AVX, we have to invert byte comparison results whenever signs of the corresponding + // bytes are different. I.e. in signed comparison it's -1 < 1, but in unsigned it is the opposite (255 > 1). To do that we XOR left and right, + // making the most significant bit of each byte 1 if the signs are different, and later apply this mask with another XOR to the comparison results. + // 3. pcmpgtw compares for "greater" relation, so we swap the arguments to get what we need. + + const __m128i mm_signs_mask = _mm_xor_si128(mm_left, mm_right); + + __m128i mm_cmp = _mm_cmpgt_epi8(mm_right, mm_left), mm_rcmp = _mm_cmpgt_epi8(mm_left, mm_right); + + mm_cmp = _mm_xor_si128(mm_signs_mask, mm_cmp); + mm_rcmp = _mm_xor_si128(mm_signs_mask, mm_rcmp); + + uint32_t cmp = static_cast<uint32_t>(_mm_movemask_epi8(mm_cmp)), rcmp = static_cast<uint32_t>(_mm_movemask_epi8(mm_rcmp)); + + cmp = (cmp - 1u) ^ cmp; + rcmp = (rcmp - 1u) ^ rcmp; + + return static_cast<uint16_t>(cmp) < static_cast<uint16_t>(rcmp); + } + + bool operator>(const LLMaterialID& rhs) const + { + return rhs < (*this); + } + + bool operator<=(const LLMaterialID& rhs) const + { + return !(rhs < (*this)); + } + + bool operator>=(const LLMaterialID& rhs) const + { + return !((*this) < rhs); + } + + bool isNull() const + { + __m128i mm = load_unaligned_si128(mID); +#if defined(AL_AVX) + return _mm_test_all_zeros(mm, mm) != 0; +#else + mm = _mm_cmpeq_epi8(mm, _mm_setzero_si128()); + return _mm_movemask_epi8(mm) == 0xFFFF; +#endif + } + + inline size_t hash() const + { + size_t seed = 0; + for (U8 i = 0; i < 4; ++i) + { + seed ^= static_cast<size_t>(mID[i * 4]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast<size_t>(mID[i * 4 + 1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast<size_t>(mID[i * 4 + 2]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast<size_t>(mID[i * 4 + 3]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } +// END BOOST const U8* get() const; void set(const void* pMemory); @@ -68,10 +164,8 @@ class LLMaterialID private: void parseFromBinary(const LLSD::Binary& pMaterialID); - void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID); - int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const; - U8 mID[MATERIAL_ID_SIZE]; + U8 mID[MATERIAL_ID_SIZE] = {}; } ; #endif // LL_LLMATERIALID_H