mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-15 01:28:47 +08:00
257 lines
5.5 KiB
C++
257 lines
5.5 KiB
C++
#pragma once
|
||
|
||
namespace MemoryUtils
|
||
{
|
||
class CMemoryUtils
|
||
{
|
||
public:
|
||
CMemoryUtils()
|
||
{
|
||
m_bMMXSupported = CheckForMMX();
|
||
m_bSSESupported = CheckForSSE();
|
||
}
|
||
~CMemoryUtils()
|
||
{
|
||
}
|
||
|
||
BOOL IsMMXSupported() const
|
||
{
|
||
return m_bMMXSupported;
|
||
}
|
||
BOOL IsSSESupported() const
|
||
{
|
||
return m_bSSESupported;
|
||
}
|
||
void memset(void *pDest, unsigned char value, int nBytes) const
|
||
{
|
||
if (nBytes<0) return;
|
||
#ifdef _M_X64
|
||
::memset(pDest, value, nBytes);
|
||
#else
|
||
if (!m_bMMXSupported)
|
||
{
|
||
::memset(pDest, value, nBytes);
|
||
return;
|
||
}
|
||
int nOffset = (int)((reinterpret_cast<ULONG64>(pDest)) % 8);
|
||
|
||
if (nBytes < 32)
|
||
{
|
||
::memset(pDest, value, nBytes);
|
||
}
|
||
else
|
||
{
|
||
if (nOffset != 0)
|
||
{
|
||
int nPreBytes = 8-nOffset;
|
||
memset(pDest, value, nPreBytes);
|
||
pDest = (void*)((BYTE*)pDest + nPreBytes);
|
||
nBytes -= nPreBytes;
|
||
}
|
||
|
||
int nLoops = nBytes/64;
|
||
unsigned __int64 value8x = value;
|
||
value8x = value8x | (value8x<<8);
|
||
value8x = value8x | (value8x<<16);
|
||
value8x = value8x | (value8x<<32);
|
||
|
||
if (nLoops > 0)
|
||
__asm
|
||
{
|
||
mov ecx, nLoops
|
||
mov edi, pDest
|
||
|
||
movq mm0, qword ptr value8x
|
||
movq mm1, qword ptr value8x
|
||
movq mm2, qword ptr value8x
|
||
movq mm3, qword ptr value8x
|
||
movq mm4, qword ptr value8x
|
||
movq mm5, qword ptr value8x
|
||
movq mm6, qword ptr value8x
|
||
movq mm7, qword ptr value8x
|
||
|
||
ALIGN 16
|
||
MMX_memset_loop:
|
||
|
||
MOVQ [edi], mm0
|
||
MOVQ [edi+8], mm1
|
||
MOVQ [edi+16], mm2
|
||
MOVQ [edi+24], mm3
|
||
MOVQ [edi+32], mm4
|
||
MOVQ [edi+40], mm5
|
||
MOVQ [edi+48], mm6
|
||
MOVQ [edi+56], mm7
|
||
|
||
ADD edi, 64
|
||
|
||
dec ecx
|
||
jnz MMX_memset_loop
|
||
|
||
EMMS
|
||
}
|
||
|
||
int nBytesDone = nLoops*64;
|
||
int nBytesLeft = nBytes - nBytesDone;
|
||
if (nBytesLeft > 0)
|
||
::memset((unsigned char *)pDest + nBytesDone, value, nBytesLeft);
|
||
}
|
||
#endif // #ifdef _M_X64 .. else
|
||
}
|
||
|
||
// <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> memcpy() <20><><EFBFBD> memmove()
|
||
void memcpy(void *pDest, void *pSrc, int nBytes) const
|
||
{
|
||
if (nBytes<0) return;
|
||
|
||
#ifdef _M_X64
|
||
::memcpy(pDest, pSrc, nBytes);
|
||
#else
|
||
if (!m_bMMXSupported)
|
||
{
|
||
::memcpy(pDest, pSrc, nBytes);
|
||
return;
|
||
}
|
||
|
||
int nOffsetSrc = (int)((reinterpret_cast<ULONG64>(pSrc)) % 8);
|
||
int nOffsetDst = (int)((reinterpret_cast<ULONG64>(pDest)) % 8);
|
||
|
||
if (nOffsetSrc != nOffsetDst || nBytes < 32)
|
||
{
|
||
// don't use MMX, since data is not aligned
|
||
::memcpy(pDest, pSrc, nBytes);
|
||
}
|
||
else
|
||
{
|
||
if (nOffsetSrc != 0)
|
||
{
|
||
int nPreBytes = 8 - nOffsetSrc;
|
||
::memcpy(pDest, pSrc, nPreBytes);
|
||
pSrc = (void*)((BYTE*)pSrc + nPreBytes);
|
||
pDest = (void*)((BYTE*)pDest + nPreBytes);
|
||
nBytes -= nPreBytes;
|
||
//assert((((unsigned long)pSrc) % 8)==0);
|
||
//assert((((unsigned long)pDest) % 8)==0);
|
||
}
|
||
|
||
int nLoops = nBytes/64;
|
||
|
||
if (nLoops > 0)
|
||
__asm
|
||
{
|
||
mov ecx, nLoops
|
||
mov eax, pSrc
|
||
mov edi, pDest
|
||
|
||
ALIGN 16
|
||
MMX_memcpy_loop:
|
||
|
||
MOVQ mm0, [eax]
|
||
MOVQ mm1, [eax+8]
|
||
MOVQ mm2, [eax+16]
|
||
MOVQ mm3, [eax+24]
|
||
MOVQ mm4, [eax+32]
|
||
MOVQ mm5, [eax+40]
|
||
MOVQ mm6, [eax+48]
|
||
MOVQ mm7, [eax+56]
|
||
|
||
MOVQ [edi], mm0
|
||
MOVQ [edi+8], mm1
|
||
MOVQ [edi+16], mm2
|
||
MOVQ [edi+24], mm3
|
||
MOVQ [edi+32], mm4
|
||
MOVQ [edi+40], mm5
|
||
MOVQ [edi+48], mm6
|
||
MOVQ [edi+56], mm7
|
||
|
||
ADD eax, 64
|
||
ADD edi, 64
|
||
|
||
dec ecx
|
||
jnz MMX_memcpy_loop
|
||
|
||
EMMS
|
||
}
|
||
|
||
int nBytesDone = nLoops*64;
|
||
int nBytesLeft = nBytes - nBytesDone;
|
||
if (nBytesLeft > 0)
|
||
{
|
||
::memcpy((unsigned char *)pDest + nBytesDone, (unsigned char *)pSrc + nBytesDone, nBytesLeft);
|
||
}
|
||
}
|
||
#endif // #ifdef _M_X64 ... else
|
||
}
|
||
|
||
|
||
protected:
|
||
BOOL m_bMMXSupported;
|
||
BOOL m_bSSESupported;
|
||
|
||
BOOL CheckForMMX()
|
||
{
|
||
#ifndef _M_X64
|
||
DWORD dwMMX = 0;
|
||
DWORD *pdwMMX = &dwMMX;
|
||
__try {
|
||
__asm {
|
||
mov eax, 1
|
||
cpuid
|
||
mov edi, pdwMMX
|
||
mov dword ptr [edi], edx
|
||
}
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
dwMMX = 0;
|
||
}
|
||
|
||
if (dwMMX & 0x00800000) // check bit 23
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
#else // _M_X64
|
||
return FALSE;
|
||
#endif
|
||
}
|
||
BOOL CheckForSSE()
|
||
{
|
||
#ifndef _M_X64
|
||
/*
|
||
The SSE instruction set was introduced with the Pentium III and features:
|
||
* Additional MMX instructions such as min/max
|
||
* Prefetch and write-through instructions for optimizing data movement
|
||
from and to the L2/L3 caches and main memory
|
||
* 8 New 128 bit XMM registers (xmm0..xmm7) and corresponding 32 bit floating point
|
||
(single precision) instructions
|
||
*/
|
||
|
||
DWORD dwSSE = 0;
|
||
DWORD *pdwSSE = &dwSSE;
|
||
__try {
|
||
__asm
|
||
{
|
||
mov eax, 1
|
||
cpuid
|
||
mov edi, pdwSSE
|
||
mov dword ptr [edi], edx
|
||
}
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
dwSSE = 0;
|
||
}
|
||
|
||
if (dwSSE & 0x02000000) // check bit 25
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
|
||
#else // _M_X64
|
||
return FALSE;
|
||
#endif
|
||
}
|
||
|
||
};
|
||
}; |