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>
libc_data_t is 8 bytes wide, so a buffer which is 4-byte but not
8-byte aligned falls back to the byte at a time loop. Add a 32-bit
middle path so such buffers still handle four bytes per iteration.
* Add DETECTNULL32/DETECTCHAR32, UNALIGNED4/UNALIGNED4_X,
LITTLEBLOCKSIZE4/BIGBLOCKSIZE4 and TOO_SMALL4 to libs/libc/libc.h.
* Take the new path in memccpy, memcmp, memcpy, memset, stpcpy,
stpncpy, strcmp, strcpy, strncmp and strncpy when both pointers are
4-byte aligned but the 8-byte path can't be used.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Most hardware accesses the memory through a 64-bit bus, so handle the
data in 64-bit chunks instead of "long" chunks which are only 32-bit
wide on the 32-bit platforms.
* Add the libc_data_t type (unsigned long long) and move the shared
UNALIGNED/UNALIGNED_X/ALIGNED, LITTLEBLOCKSIZE, TOO_SMALL and
DETECTNULL helpers from the individual C files to libs/libc/libc.h.
* Convert all lib_bsd*.c implementations to the new type and macros,
which also drops the duplicated LONG_MAX conditionals.
Assisted-by: Claude:claude-opus-5
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This allows the compiler to automatically identify which string functions
can be compiled into libraries, and the compiler's internal implementation
is faster than libc functions.
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
remove reference to non-existent readme in libc.
Pointing to the documentation page doesn't make sense in this case,
because it doesn't explain the use of `#undef XXX` for this case anyway.
Signed-off-by: raiden00pl <raiden00@railab.me>