Skip to content
Snippets Groups Projects
Commit 3d718db9 authored by Rye Mutt's avatar Rye Mutt :bread:
Browse files

Cleanup and optimize LLMaterialID to be trivially copy/movable and introduce SIMD operators

parent 51325421
No related branches found
No related tags found
No related merge requests found
...@@ -35,11 +35,6 @@ ...@@ -35,11 +35,6 @@
const LLMaterialID LLMaterialID::null; const LLMaterialID LLMaterialID::null;
LLMaterialID::LLMaterialID()
{
clear();
}
LLMaterialID::LLMaterialID(const LLSD& pMaterialID) LLMaterialID::LLMaterialID(const LLSD& pMaterialID)
{ {
llassert(pMaterialID.isBinary()); llassert(pMaterialID.isBinary());
...@@ -56,61 +51,11 @@ LLMaterialID::LLMaterialID(const void* pMemory) ...@@ -56,61 +51,11 @@ LLMaterialID::LLMaterialID(const void* pMemory)
set(pMemory); set(pMemory);
} }
LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID)
{
copyFromOtherMaterialID(pOtherMaterialID);
}
LLMaterialID::LLMaterialID(const LLUUID& lluid) LLMaterialID::LLMaterialID(const LLUUID& lluid)
{ {
set(lluid.mData); 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 const U8* LLMaterialID::get() const
{ {
return mID; return mID;
...@@ -161,28 +106,8 @@ std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id) ...@@ -161,28 +106,8 @@ std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id)
return s; return s;
} }
void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID) void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID)
{ {
llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8))); llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8)));
memcpy(mID, &pMaterialID[0], 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;
}
...@@ -30,30 +30,126 @@ ...@@ -30,30 +30,126 @@
#define MATERIAL_ID_SIZE 16 #define MATERIAL_ID_SIZE 16
#include <string> #include <string>
#include <immintrin.h>
#include "llsd.h" #include "llsd.h"
class LLMaterialID class LLMaterialID
{ {
public: public:
LLMaterialID(); LLMaterialID() = default;
LLMaterialID(const LLSD& pMaterialID); LLMaterialID(const LLSD& pMaterialID);
LLMaterialID(const LLSD::Binary& pMaterialID); LLMaterialID(const LLSD::Binary& pMaterialID);
LLMaterialID(const void* pMemory); LLMaterialID(const void* pMemory);
LLMaterialID(const LLMaterialID& pOtherMaterialID);
LLMaterialID(const LLUUID& lluid); LLMaterialID(const LLUUID& lluid);
~LLMaterialID();
bool operator == (const LLMaterialID& pOtherMaterialID) const; // BEGIN BOOST
bool operator != (const LLMaterialID& pOtherMaterialID) const; // 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& rhs) const
{
__m128i mm_left = load_unaligned_si128(mID);
__m128i mm_right = load_unaligned_si128(rhs.mID);
__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 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);
bool operator < (const LLMaterialID& pOtherMaterialID) const; mm_cmp = _mm_xor_si128(mm_signs_mask, mm_cmp);
bool operator <= (const LLMaterialID& pOtherMaterialID) const; mm_rcmp = _mm_xor_si128(mm_signs_mask, mm_rcmp);
bool operator > (const LLMaterialID& pOtherMaterialID) const;
bool operator >= (const LLMaterialID& pOtherMaterialID) const;
LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID); uint32_t cmp = static_cast<uint32_t>(_mm_movemask_epi8(mm_cmp)), rcmp = static_cast<uint32_t>(_mm_movemask_epi8(mm_rcmp));
bool isNull() const; 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; const U8* get() const;
void set(const void* pMemory); void set(const void* pMemory);
...@@ -68,10 +164,8 @@ class LLMaterialID ...@@ -68,10 +164,8 @@ class LLMaterialID
private: private:
void parseFromBinary(const LLSD::Binary& pMaterialID); 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 #endif // LL_LLMATERIALID_H
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment