Add SSE2 qt_memfill64
Implemented by merging with the qt_memfill32 implementation in a non-inlining function. Change-Id: I343f2beed55440a7ac0bfffd15636f8ba995a2bd Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>bb10
parent
12e843581a
commit
a440aada72
|
|
@ -6260,10 +6260,12 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
|
|||
},
|
||||
};
|
||||
|
||||
#if !defined(__SSE2__)
|
||||
void qt_memfill64(quint64 *dest, quint64 color, qsizetype count)
|
||||
{
|
||||
qt_memfill_template<quint64>(dest, color, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
void qt_memfill16(quint16 *dest, quint16 value, qsizetype count)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -70,10 +70,17 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
#if defined(Q_CC_GNU)
|
||||
# define Q_DECL_RESTRICT __restrict__
|
||||
# if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
|
||||
# define Q_DECL_VECTORCALL __attribute__((sseregparm,regparm(3)))
|
||||
# else
|
||||
# define Q_DECL_VECTORCALL
|
||||
# endif
|
||||
#elif defined(Q_CC_MSVC)
|
||||
# define Q_DECL_RESTRICT __restrict
|
||||
# define Q_DECL_VECTORCALL __vectorcall
|
||||
#else
|
||||
# define Q_DECL_RESTRICT
|
||||
# define Q_DECL_VECTORCALL
|
||||
#endif
|
||||
|
||||
static const uint AMASK = 0xff000000;
|
||||
|
|
|
|||
|
|
@ -233,19 +233,70 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u
|
|||
}
|
||||
}
|
||||
|
||||
static Q_NEVER_INLINE
|
||||
void Q_DECL_VECTORCALL qt_memfillXX_aligned(void *dest, __m128i value128, quintptr bytecount)
|
||||
{
|
||||
__m128i *dst128 = reinterpret_cast<__m128i *>(dest);
|
||||
__m128i *end128 = reinterpret_cast<__m128i *>(static_cast<uchar *>(dest) + bytecount);
|
||||
|
||||
while (dst128 + 4 <= end128) {
|
||||
_mm_store_si128(dst128 + 0, value128);
|
||||
_mm_store_si128(dst128 + 1, value128);
|
||||
_mm_store_si128(dst128 + 2, value128);
|
||||
_mm_store_si128(dst128 + 3, value128);
|
||||
dst128 += 4;
|
||||
}
|
||||
|
||||
bytecount %= 4 * sizeof(__m128i);
|
||||
switch (bytecount / sizeof(__m128i)) {
|
||||
case 3: _mm_store_si128(dst128++, value128); Q_FALLTHROUGH();
|
||||
case 2: _mm_store_si128(dst128++, value128); Q_FALLTHROUGH();
|
||||
case 1: _mm_store_si128(dst128++, value128);
|
||||
}
|
||||
}
|
||||
|
||||
void qt_memfill64(quint64 *dest, quint64 value, qsizetype count)
|
||||
{
|
||||
quintptr misaligned = quintptr(dest) % sizeof(__m128i);
|
||||
if (misaligned && count) {
|
||||
#if defined(Q_PROCESSOR_X86_32)
|
||||
// Before SSE came out, the alignment of the stack used to be only 4
|
||||
// bytes and some OS/ABIs (notably, code generated by MSVC) still only
|
||||
// align to that. In any case, we cannot count on the alignment of
|
||||
// quint64 to be 8 -- see QtPrivate::AlignOf_WorkaroundForI386Abi in
|
||||
// qglobal.h.
|
||||
//
|
||||
// If the pointer is not aligned to at least 8 bytes, then we'll never
|
||||
// in turn hit a multiple of 16 for the qt_memfillXX_aligned call
|
||||
// below.
|
||||
if (Q_UNLIKELY(misaligned % sizeof(quint64)))
|
||||
return qt_memfill_template(dest, value, count);
|
||||
#endif
|
||||
|
||||
*dest++ = value;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (count % 2) {
|
||||
dest[count - 1] = value;
|
||||
--count;
|
||||
}
|
||||
|
||||
qt_memfillXX_aligned(dest, _mm_set1_epi64x(value), count * sizeof(quint64));
|
||||
}
|
||||
|
||||
void qt_memfill32(quint32 *dest, quint32 value, qsizetype count)
|
||||
{
|
||||
if (count < 7) {
|
||||
if (count < 4) {
|
||||
// this simplifies the code below: the first switch can fall through
|
||||
// without checking the value of count
|
||||
switch (count) {
|
||||
case 6: *dest++ = value; Q_FALLTHROUGH();
|
||||
case 5: *dest++ = value; Q_FALLTHROUGH();
|
||||
case 4: *dest++ = value; Q_FALLTHROUGH();
|
||||
case 3: *dest++ = value; Q_FALLTHROUGH();
|
||||
case 2: *dest++ = value; Q_FALLTHROUGH();
|
||||
case 1: *dest = value;
|
||||
}
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const int align = (quintptr)(dest) & 0xf;
|
||||
switch (align) {
|
||||
|
|
@ -263,24 +314,7 @@ void qt_memfill32(quint32 *dest, quint32 value, qsizetype count)
|
|||
}
|
||||
}
|
||||
|
||||
int count128 = count / 4;
|
||||
__m128i *dst128 = reinterpret_cast<__m128i*>(dest);
|
||||
__m128i *end128 = dst128 + count128;
|
||||
const __m128i value128 = _mm_set1_epi32(value);
|
||||
|
||||
while (dst128 + 3 < end128) {
|
||||
_mm_store_si128(dst128 + 0, value128);
|
||||
_mm_store_si128(dst128 + 1, value128);
|
||||
_mm_store_si128(dst128 + 2, value128);
|
||||
_mm_store_si128(dst128 + 3, value128);
|
||||
dst128 += 4;
|
||||
}
|
||||
|
||||
switch (count128 & 0x3) {
|
||||
case 3: _mm_store_si128(dst128++, value128); Q_FALLTHROUGH();
|
||||
case 2: _mm_store_si128(dst128++, value128); Q_FALLTHROUGH();
|
||||
case 1: _mm_store_si128(dst128++, value128);
|
||||
}
|
||||
qt_memfillXX_aligned(dest, _mm_set1_epi32(value), count * sizeof(quint32));
|
||||
}
|
||||
|
||||
void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef __SSE2__
|
||||
void qt_memfill64(quint64 *dest, quint64 value, qsizetype count);
|
||||
void qt_memfill32(quint32 *dest, quint32 value, qsizetype count);
|
||||
void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y,
|
||||
const QRgba64 &color,
|
||||
|
|
|
|||
Loading…
Reference in New Issue