nuttx/libs/libc/string/lib_bsdstpcpy.c

110 lines
3.4 KiB
C
Raw Normal View History

/****************************************************************************
* libs/libc/string/lib_bsdstpcpy.c
*
* SPDX-License-Identifier: BSD
* SPDX-FileCopyrightText: 1994-2009 Red Hat, Inc. All rights reserved
*
* Copyright (c) 1994-2009 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the BSD License. This program is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
* including the implied warranties of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. A copy of this license is available at
* http://www.opensource.org/licenses. Any Red Hat trademarks that are
* incorporated in the source code or documentation are not subject to
* the BSD License and may only be used or replicated with the express
* permission of Red Hat, Inc.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <string.h>
#include "libc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stpcpy
*
* Description:
* Copies the string pointed to by 'src' (including the terminating NUL
* character) into the array pointed to by 'dest'.
*
* Returned Value:
* The stpcpy() function returns a pointer to the terminating NUL
* character copied into the 'dest' buffer
*
****************************************************************************/
#ifndef CONFIG_LIBC_ARCH_STPCPY
#undef stpcpy
no_builtin("stpcpy")
nosanitize_address
FAR char *stpcpy(FAR char *dest, FAR const char *src)
{
libs/libc/string: Copy and compare by words when pointers agree on alignment. The BSD string functions take a word path only when both pointers are aligned, and a byte path otherwise. A pair at the same offset from a boundary takes the byte path even though copying or comparing a few leading bytes aligns both at once, since aligning one aligns the other. Add MISALIGNED(), which asks whether two pointers disagree about where a boundary falls, and walk an agreeing pair up to the boundary before the existing path selection. MISALIGNED4() does the same for the 4-byte path, so a pair that is 4-byte but not 8-byte aligned reaches the wide path instead of the middle one. No existing line changes: the walk is a new step ahead of the current decisions. A pair at differing offsets still takes the byte path, since no single boundary serves both. Measured on an EIC7700 EVB (EIC7700X, RV64GC, 1.4GHz) with the BSD string functions selected and the RISC-V assembly ones disabled, using the benchmark in apps#3706, medians of 3 runs in MB/s at its largest size: equal offset aligned memcpy 414 -> 4148 10.0x 4214 -> 4208 memcmp 41 -> 361 8.8x 362 -> 360 strncmp 28 -> 202 7.4x 207 -> 207 strcmp 42 -> 273 6.5x 278 -> 276 strncpy 377 -> 1676 4.5x 1824 -> 1748 stpncpy 376 -> 1654 4.4x 1843 -> 1724 stpcpy 551 -> 1833 3.3x 1970 -> 1939 memccpy 650 -> 2012 3.1x 2478 -> 2016 strcpy 636 -> 1837 2.9x 1678 -> 1965 Cases the walk never runs for move in both directions by up to a third, the largest being memccpy at differing offsets, 648 -> 414. Their code is unchanged, so that is code placement rather than an effect of the change. The change is architecture independent but has only been measured on RV64GC. Word size, alignment cost and byte loop codegen all differ elsewhere, so the balance wants measuring on other architectures. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
2026-08-17 18:55:45 +08:00
/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The terminator is left for the byte loop to copy.
*/
if (!MISALIGNED(src, dest) && UNALIGNED_X(src))
{
while (*src != '\0')
{
*dest++ = *src++;
if (!UNALIGNED_X(src))
{
break;
}
}
}
/* If src or dest is unaligned, then copy bytes. */
if (!UNALIGNED(src, dest))
{
FAR libc_data_t *aligned_dst = (FAR libc_data_t *)dest;
FAR const libc_data_t *aligned_src = (FAR libc_data_t *)src;
while (!DETECTNULL(*aligned_src))
{
*aligned_dst++ = *aligned_src++;
}
dest = (FAR char *)aligned_dst;
src = (FAR char *)aligned_src;
}
else if (!UNALIGNED4(src, dest))
{
FAR uint32_t *aligned_dst = (FAR uint32_t *)dest;
FAR const uint32_t *aligned_src = (FAR uint32_t *)src;
while (!DETECTNULL32(*aligned_src))
{
*aligned_dst++ = *aligned_src++;
}
dest = (FAR char *)aligned_dst;
src = (FAR char *)aligned_src;
}
while ((*dest++ = *src++) != '\0');
return --dest;
}
#endif