Optimise guarded memcpy (#449)

* Improve testing of memcpy including adding perf test.

* Change remaining_bytes to be branch free.

Use reciprocal division followed by multiply to remove a branch.
This commit is contained in:
Matthew Parkinson
2022-01-07 17:09:13 +00:00
committed by GitHub
parent 4ea978b946
commit 419347ba4a
4 changed files with 263 additions and 53 deletions

View File

@@ -141,7 +141,7 @@ namespace
{
if constexpr (FailFast)
{
UNUSED(ptr, len, msg);
UNUSED(p, len, msg);
SNMALLOC_FAST_FAIL();
}
else
@@ -193,15 +193,12 @@ namespace
return (pointer_align_down<Size>(const_cast<void*>(src)) == src) &&
(pointer_align_down<Size>(dst) == dst);
}
}
extern "C"
{
/**
* Snmalloc checked memcpy.
*/
SNMALLOC_EXPORT void*
SNMALLOC_NAME_MANGLE(memcpy)(void* dst, const void* src, size_t len)
template<bool checked>
void* memcpy(void* dst, const void* src, size_t len)
{
// 0 is a very common size for memcpy and we don't need to do external
// pointer checks if we hit it. It's also the fastest case, to encourage
@@ -210,11 +207,15 @@ extern "C"
{
return dst;
}
// Check the bounds of the arguments.
check_bounds(
dst, len, "memcpy with destination out of bounds of heap allocation");
check_bounds<true>(
src, len, "memcpy with source out of bounds of heap allocation");
if constexpr (checked)
{
// Check the bounds of the arguments.
check_bounds(
dst, len, "memcpy with destination out of bounds of heap allocation");
check_bounds<true>(
src, len, "memcpy with source out of bounds of heap allocation");
}
// If this is a small size, do byte-by-byte copies.
if (len < LargestRegisterSize)
{
@@ -225,4 +226,16 @@ extern "C"
copy_end<LargestRegisterSize>(dst, src, len);
return dst;
}
} // namespace
extern "C"
{
/**
* Snmalloc checked memcpy.
*/
SNMALLOC_EXPORT void*
SNMALLOC_NAME_MANGLE(memcpy)(void* dst, const void* src, size_t len)
{
return memcpy<true>(dst, src, len);
}
}