Re: [PATCH 3/3] RISC-V: memcpy() align dest when misaligned access is prohibited

Sebastian Huber <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Hello Christian,

I don't want to touch the Newlib configuration to get a working library. GCC 13 is still maintained, so it should work out of the box. Optimizations which work only for a subset of machines should be only enabled if they are supported (this is the case, when __riscv_misaligned_fast is defined).

----- Am 30. Jun 2025 um 11:52 schrieb Christian Herber [email protected]:

> I believe there is a config parameter to newlib, which you can use if your
> toolchain does not support the conventional macros.
> I do not know them off by hard, but maybe this pointer helps you already.
> 
>> -----Original Message-----
>> From: Sebastian Huber <[email protected]>
>> Sent: Monday, 30 June 2025 11:41
>> To: ma mandourr <[email protected]>
>> Cc: newlib <[email protected]>; Christian Herber (OSS)
>> <[email protected]>
>> Subject: Re: [PATCH 3/3] RISC-V: memcpy() align dest when misaligned access is
>> prohibited
>> 
>> Hello Mahmoud Abumandour,
>> 
>> I use Newlib on a Microchip PolarFire SoC which doesn't support misaligned
>> access. I get exceptions (mcause is 4 or 6) with the current Newlib. I use the
>> following machine options with GCC 13:
>> 
>> -march=rv64imac -mabi=lp64 -mcmodel=medany -mstrict-align
>> 
>> It seems that neither __riscv_misaligned_slow nor __riscv_misaligned_avoid is
>> defined by GCC 13, so the workaround is not activated. This define is only
>> available in GCC 14 and later.
>> 
>> Would it make sense to change this check to
>> 
>> #if !defined(__riscv_misaligned_fast)
>> 
>> instead of
>> 
>> #if defined(__riscv_misaligned_slow) || defined(__riscv_misaligned_avoid)
>> 
>> ?
>> 
>> ----- Am 27. Apr 2025 um 13:41 schrieb ma mandourr [email protected]:
>> 
>> > From: Mahmoud Abumandour <[email protected]>
>> >
>> > Add a code path for when source and dest are differently aligned.
>> >
>> > If misaligned access is slow or prohibited, and the alignments of the
>> > source and destination are different, we align the destination to do
>> > XLEN stores. This uses only one aligned store for every four (or eight
>> > for XLEN == 64) bytes of data.
>> >
>> > Reviewed-by: Christian Herber <[email protected]>
>> > Signed-off-by: Mahmoud Abumandour <[email protected]>
>> > ---
>> > newlib/libc/machine/riscv/memcpy.c | 72 +++++++++++++++++++++++++-----
>> > 1 file changed, 60 insertions(+), 12 deletions(-)
>> >
>> > diff --git a/newlib/libc/machine/riscv/memcpy.c
>> > b/newlib/libc/machine/riscv/memcpy.c
>> > index 427005efd..5d6b2f301 100644
>> > --- a/newlib/libc/machine/riscv/memcpy.c
>> > +++ b/newlib/libc/machine/riscv/memcpy.c
>> > @@ -16,7 +16,6 @@
>> >
>> > #include "../../string/local.h"
>> > #include "xlenint.h"
>> > -#include <stdint.h>
>> > #include <string.h>
>> > #include <sys/asm.h>
>> >
>> > @@ -31,6 +30,30 @@ __libc_memcpy_bytewise (unsigned char *dst, const
>> > unsigned char *src,
>> >     *dst++ = *src++;
>> > }
>> >
>> > +#if defined(__riscv_misaligned_slow) ||
>> > +defined(__riscv_misaligned_avoid) static uintxlen_t __libc_load_xlen
>> > +(const void *src) {
>> > +  const unsigned char *p = (const unsigned char *)src;
>> > +  uintxlen_t ret = 0;
>> > +  unsigned char b0 = *p++;
>> > +  unsigned char b1 = *p++;
>> > +  unsigned char b2 = *p++;
>> > +  unsigned char b3 = *p++;
>> > +  ret = (uintxlen_t)b0 | ((uintxlen_t)b1 << 8) | ((uintxlen_t)b2 << 16)
>> > +        | ((uintxlen_t)b3 << 24);
>> > +#if __riscv_xlen == 64
>> > +  unsigned char b4 = *p++;
>> > +  unsigned char b5 = *p++;
>> > +  unsigned char b6 = *p++;
>> > +  unsigned char b7 = *p++;
>> > +  ret |= ((uintxlen_t)b4 << 32) | ((uintxlen_t)b5 << 40)
>> > +         | ((uintxlen_t)b6 << 48) | ((uintxlen_t)b7 << 56); #endif
>> > +  return ret;
>> > +}
>> > +#endif
>> > +
>> > void *
>> > __inhibit_loop_to_libcall
>> > memcpy (void *__restrict aa, const void *__restrict bb, size_t n) @@
>> > -39,23 +62,51 @@ memcpy (void *__restrict aa, const void *__restrict
>> > bb, size_t n)
>> >   const unsigned char *b = (const unsigned char *)bb;
>> >   unsigned char *end = a + n;
>> >   uintptr_t msk = SZREG - 1;
>> > -#if __riscv_misaligned_slow || __riscv_misaligned_fast
>> >   if (n < SZREG)
>> > -#else
>> > -  if (unlikely ((((uintptr_t)a & msk) != ((uintptr_t)b & msk)) || n <
>> > SZREG)) -#endif
>> >     {
>> >       if (__builtin_expect (a < end, 1))
>> >         __libc_memcpy_bytewise (a, b, n);
>> >       return aa;
>> >     }
>> >
>> > +/*
>> > + * If misaligned access is slow or prohibited, and the alignments of
>> > +the source
>> > + * and destination are different, we align the destination to do XLEN stores.
>> > + * This uses only one aligned store for every four (or eight for XLEN
>> > +== 64)
>> > + * bytes of data.
>> > + */
>> > +#if defined(__riscv_misaligned_slow) ||
>> > +defined(__riscv_misaligned_avoid)
>> > +  if (unlikely ((((uintptr_t)a & msk) != ((uintptr_t)b & msk))))
>> > +    {
>> > +      size_t dst_pad = (uintptr_t)a & msk;
>> > +      dst_pad = (SZREG - dst_pad) & msk;
>> > +      __libc_memcpy_bytewise (a, b, dst_pad);
>> > +      a += dst_pad;
>> > +      b += dst_pad;
>> > +
>> > +      uintxlen_t *la = (uintxlen_t *)a;
>> > +      const unsigned char *cb = (const unsigned char *)b;
>> > +      uintxlen_t *lend = (uintxlen_t *)((uintptr_t)end & ~msk);
>> > +
>> > +      while (la < lend)
>> > +        {
>> > +          *la++ = __libc_load_xlen (cb);
>> > +          cb += SZREG;
>> > +        }
>> > +      a = (unsigned char *)la;
>> > +      b = (const unsigned char *)cb;
>> > +      if (unlikely (a < end))
>> > +        __libc_memcpy_bytewise (a, b, end - a);
>> > +      return aa;
>> > +    }
>> > +#endif
>> > +
>> >   if (unlikely (((uintptr_t)a & msk) != 0))
>> >     {
>> > -      size_t rem = SZREG - ((uintptr_t)a & msk);
>> > -      __libc_memcpy_bytewise (a, b, rem);
>> > -      a += rem;
>> > -      b += rem;
>> > +      size_t pad = SZREG - ((uintptr_t)a & msk);
>> > +      __libc_memcpy_bytewise (a, b, pad);
>> > +      a += pad;
>> > +      b += pad;
>> >     }
>> >
>> >   uintxlen_t *la = (uintxlen_t *)a;
>> > @@ -87,9 +138,6 @@ memcpy (void *__restrict aa, const void *__restrict
>> > bb, size_t n)
>> >         }
>> >     }
>> >
>> > -  while (la < lend)
>> > -      *la++ = *lb++;
>> > -
>> >   a = (unsigned char *)la;
>> >   b = (const unsigned char *)lb;
>> >   if (unlikely (a < end))
>> > --
>> > 2.43.0
>> 
>> --
>> embedded brains GmbH & Co. KG
>> Herr Sebastian HUBER
>> Dornierstr. 4
>> 82178 Puchheim
>> Germany
>> email: [email protected]
>> phone: +49-89-18 94 741 - 16
>> fax:   +49-89-18 94 741 - 08
>> 
>> Registergericht: Amtsgericht München
>> Registernummer: HRB 157899
>> Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
>> Unsere Datenschutzerklärung finden Sie hier:
> > https://embedded-brains.de/datenschutzerklaerung/

-- 
embedded brains GmbH & Co. KG
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: [email protected]
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.