mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
58f184a4cb
In commit d25f806d73
(MDEV-22749)
the CRC-32C implementation of MariaDB was broken on some
IA-32 and AMD64 builds, depending on the compiler version and
build options. This was verified for IA-32 on GCC 10.2.1.
Even though we try to identify the SSE4.2 extensions and the
availaibility of the PCLMULQDQ instruction by executing CPUID,
the fall-back code could be generated with extended instructions,
because the entire file mysys/crc32/crc32c.c was being compiled
with -msse4.2 -mpclmul. This would cause SIGILL on a PINSRD
instruction on affected IA-32 targets (such as some Intel Atom
processors). This might also affect old AMD64 processors
(predating the 2007 Intel Nehalem microarchitecture), if some
compiler chose to emit the offending instructions.
While it is fine to pass a target-specific option to a target-specific
compilation unit (like -mpclmul to a PCLMUL-specific compilation unit),
that is not safe for mixed-architecture compilation units.
For mixed-architecture compilation units, the correct way is to set
target attributes on the target-specific functions.
There does not seem to be a way to pass target attributes to
function template instantiation. Hence, we must replace the
ExtendImpl template with plain functions crc32_sse42() and
crc32_slow().
We will also remove some inconsistency between
my_crc32_implementation() and mysys_namespace::crc32::Choose_Extend().
The function crc32_pclmul_enabled() will be moved to mysys/crc32/crc32c.cc
so that the detection code will be compiled without -msse4.2 -mpclmul.
The AMD64 PCLMUL accelerated crc32c_3way() will be moved to a new
file crc32c_amd64.cc. In this way, only a few functions that depend
on -msse4.2 in mysys/crc32/crc32c.cc can be declared with
__attribute__((target("sse4.2"))), and most of the file can be compiled
for the generic target.
Last, the file mysys/crc32ieee.cc will be omitted on 64-bit POWER,
because it was dead code (no symbols were exported).
Reviewed by: Vladislav Vaintroub
61 lines
1.9 KiB
C++
61 lines
1.9 KiB
C++
/* Copyright (c) 2020, 2021, MariaDB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
|
|
#include <my_global.h>
|
|
#include <my_sys.h>
|
|
#include <zlib.h>
|
|
|
|
/* TODO: remove this once zlib adds inherent support for hardware accelerated
|
|
crc32 for all architectures. */
|
|
static unsigned int my_crc32_zlib(unsigned int crc, const void *data,
|
|
size_t len)
|
|
{
|
|
return (unsigned int) crc32(crc, (const Bytef *)data, (unsigned int) len);
|
|
}
|
|
|
|
#ifdef HAVE_PCLMUL
|
|
extern "C" int crc32_pclmul_enabled();
|
|
extern "C" unsigned int crc32_pclmul(unsigned int, const void *, size_t);
|
|
#elif defined(__GNUC__) && defined(HAVE_ARMV8_CRC)
|
|
extern "C" int crc32_aarch64_available();
|
|
extern "C" unsigned int crc32_aarch64(unsigned int, const void *, size_t);
|
|
#endif
|
|
|
|
|
|
typedef unsigned int (*my_crc32_t)(unsigned int, const void *, size_t);
|
|
|
|
static my_crc32_t init_crc32()
|
|
{
|
|
#ifdef HAVE_PCLMUL
|
|
if (crc32_pclmul_enabled())
|
|
return crc32_pclmul;
|
|
#elif defined(__GNUC__) && defined(HAVE_ARMV8_CRC)
|
|
if (crc32_aarch64_available())
|
|
return crc32_aarch64;
|
|
#endif
|
|
return my_crc32_zlib;
|
|
}
|
|
|
|
static const my_crc32_t my_checksum_func= init_crc32();
|
|
|
|
#ifdef __powerpc64__
|
|
# error "my_checksum() is defined in mysys/crc32/crc32_ppc64.c"
|
|
#endif
|
|
extern "C"
|
|
unsigned int my_checksum(unsigned int crc, const void *data, size_t len)
|
|
{
|
|
return my_checksum_func(crc, data, len);
|
|
}
|