aboutsummaryrefslogtreecommitdiff
path: root/newlib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc')
-rw-r--r--newlib/libc/ctype/ctype_.c9
-rw-r--r--newlib/libc/include/machine/ieeefp.h6
-rw-r--r--newlib/libc/include/machine/setjmp.h11
-rw-r--r--newlib/libc/include/pthread.h12
-rw-r--r--newlib/libc/include/search.h10
-rw-r--r--newlib/libc/include/stdlib.h5
-rw-r--r--newlib/libc/include/sys/config.h2
-rw-r--r--newlib/libc/include/sys/reent.h3
-rw-r--r--newlib/libc/include/sys/stat.h16
-rw-r--r--newlib/libc/include/sys/unistd.h2
-rw-r--r--newlib/libc/include/time.h5
-rw-r--r--newlib/libc/machine/aarch64/sys/fenv.h16
-rw-r--r--newlib/libc/machine/mips/Makefile.inc2
-rw-r--r--newlib/libc/machine/mips/machine/regdef.h38
-rw-r--r--newlib/libc/machine/mips/memcpy.c449
-rw-r--r--newlib/libc/machine/mips/memset.c176
-rw-r--r--newlib/libc/machine/mips/setjmp.S6
-rw-r--r--newlib/libc/machine/mips/strcmp.S289
-rw-r--r--newlib/libc/machine/mips/strlen.c20
-rw-r--r--newlib/libc/machine/riscv/Makefile.inc2
-rw-r--r--newlib/libc/machine/riscv/memchr.c152
-rw-r--r--newlib/libc/machine/riscv/memcpy-asm.S12
-rw-r--r--newlib/libc/machine/riscv/memcpy.c163
-rw-r--r--newlib/libc/machine/riscv/memmove.S28
-rw-r--r--newlib/libc/machine/riscv/memrchr.c172
-rw-r--r--newlib/libc/machine/riscv/memset.S349
-rw-r--r--newlib/libc/machine/riscv/rv_string.h51
-rw-r--r--newlib/libc/machine/riscv/setjmp.S78
-rw-r--r--newlib/libc/machine/riscv/strcmp.S198
-rw-r--r--newlib/libc/machine/riscv/strlen.c19
-rw-r--r--newlib/libc/machine/riscv/xlenint.h7
-rw-r--r--newlib/libc/posix/ftw.c4
-rw-r--r--newlib/libc/posix/glob.c90
-rw-r--r--newlib/libc/posix/posix_spawn.c45
-rw-r--r--newlib/libc/posix/posix_spawn.h54
-rw-r--r--newlib/libc/search/tdelete.c2
-rw-r--r--newlib/libc/search/tfind.c2
-rw-r--r--newlib/libc/search/tsearch.c2
-rw-r--r--newlib/libc/search/twalk.c4
-rw-r--r--newlib/libc/stdlib/mbtowc_r.c25
-rw-r--r--newlib/libc/stdlib/wcstombs_r.c7
-rw-r--r--newlib/libc/stdlib/wctomb_r.c4
-rw-r--r--newlib/libc/sys/rtems/include/limits.h10
-rw-r--r--newlib/libc/sys/rtems/include/semaphore.h6
-rw-r--r--newlib/libc/sys/rtems/include/sys/dirent.h2
-rw-r--r--newlib/libc/sys/rtems/include/sys/poll.h9
46 files changed, 1987 insertions, 587 deletions
diff --git a/newlib/libc/ctype/ctype_.c b/newlib/libc/ctype/ctype_.c
index 32ce4f3..869945f 100644
--- a/newlib/libc/ctype/ctype_.c
+++ b/newlib/libc/ctype/ctype_.c
@@ -95,21 +95,12 @@ char _ctype_b[128 + 256] = {
/* For backward compatibility */
char __EXPORT *__ctype_ptr__ = DEFAULT_CTYPE_PTR;
-# ifdef __x86_64__
__asm__ (" \n\
.data \n\
.globl _ctype_ \n\
.set _ctype_,_ctype_b+127 \n\
.text \n\
");
-# else
-__asm__ (" \n\
- .data \n\
- .globl __ctype_ \n\
- .set __ctype_,__ctype_b+127 \n\
- .text \n\
-");
-# endif
# else /* !__CYGWIN__ */
const char _ctype_[1 + 256] = {
diff --git a/newlib/libc/include/machine/ieeefp.h b/newlib/libc/include/machine/ieeefp.h
index f99577b..c5fafcf 100644
--- a/newlib/libc/include/machine/ieeefp.h
+++ b/newlib/libc/include/machine/ieeefp.h
@@ -263,9 +263,15 @@
#ifdef __MIPSEL__
#define __IEEE_LITTLE_ENDIAN
+#if __SIZEOF_DOUBLE__ == 4
+#define _DOUBLE_IS_32BITS
+#endif
#endif
#ifdef __MIPSEB__
#define __IEEE_BIG_ENDIAN
+#if __SIZEOF_DOUBLE__ == 4
+#define _DOUBLE_IS_32BITS
+#endif
#endif
#ifdef __MMIX__
diff --git a/newlib/libc/include/machine/setjmp.h b/newlib/libc/include/machine/setjmp.h
index 102582c..ab820ed 100644
--- a/newlib/libc/include/machine/setjmp.h
+++ b/newlib/libc/include/machine/setjmp.h
@@ -22,7 +22,16 @@ _BEGIN_STD_C
#endif
#if defined(__aarch64__)
-#define _JBLEN 22
+# if defined(__CYGWIN__)
+/*
+ * Windows Arm64 ABI requires saving x19-x28, FP, LR, SP, FPCR, FPSR, d8-d15
+ * and jump address to jmp_buf. On top of that, Cygwin requires saving
+ * TLS stack pointer.
+ */
+# define _JBLEN 25
+# else
+# define _JBLEN 22
+# endif
#define _JBTYPE long long
#endif
diff --git a/newlib/libc/include/pthread.h b/newlib/libc/include/pthread.h
index c99ad39..05ff315 100644
--- a/newlib/libc/include/pthread.h
+++ b/newlib/libc/include/pthread.h
@@ -87,11 +87,11 @@ int pthread_mutex_timedlock (pthread_mutex_t *__mutex,
#endif /* _POSIX_TIMEOUTS */
-#if __GNU_VISIBLE
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
/* The Issue 8 standard adds pthread_mutex_clocklock() */
int pthread_mutex_clocklock(pthread_mutex_t *__restrict, clockid_t,
const struct timespec *__restrict);
-#endif /* __GNU_VISIBLE */
+#endif /* __GNU_VISIBLE || __POSIX_VISIBLE >= 202405 */
/* Condition Variable Initialization Attributes, P1003.1c/Draft 10, p. 96 */
@@ -133,12 +133,12 @@ int pthread_cond_timedwait (pthread_cond_t *__cond,
pthread_mutex_t *__mutex,
const struct timespec *__abstime);
-#if __GNU_VISIBLE
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
/* The Issue 8 standard adds pthread_cond_clockwait() */
int pthread_cond_clockwait(pthread_cond_t *__restrict,
pthread_mutex_t *__restrict, clockid_t,
const struct timespec *__restrict);
-#endif /* __GNU_VISIBLE */
+#endif /* __GNU_VISIBLE || __POSIX_VISIBLE >= 202405 */
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
@@ -436,14 +436,14 @@ int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
int pthread_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
const struct timespec *__abstime);
-#if __GNU_VISIBLE
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
/* The Issue 8 standard adds pthread_rwlock_clockrdlock()
* and pthread_rwlock_clockwrlock()*/
int pthread_rwlock_clockrdlock(pthread_rwlock_t *__restrict, clockid_t,
const struct timespec *__restrict);
int pthread_rwlock_clockwrlock(pthread_rwlock_t *__restrict, clockid_t,
const struct timespec *__restrict);
-#endif /* __GNU_VISIBLE */
+#endif /* __GNU_VISIBLE || __POSIX_VISIBLE >= 202405 */
#endif /* defined(_POSIX_READER_WRITER_LOCKS) */
diff --git a/newlib/libc/include/search.h b/newlib/libc/include/search.h
index ed321b0..70a1a20 100644
--- a/newlib/libc/include/search.h
+++ b/newlib/libc/include/search.h
@@ -36,6 +36,8 @@ typedef struct node {
} node_t;
#endif
+typedef void posix_tnode;
+
struct hsearch_data
{
struct internal_head *htable;
@@ -54,11 +56,11 @@ ENTRY *hsearch(ENTRY, ACTION);
int hcreate_r(size_t, struct hsearch_data *);
void hdestroy_r(struct hsearch_data *);
int hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *);
-void *tdelete(const void *__restrict, void **__restrict, __compar_fn_t);
+void *tdelete(const void *__restrict, posix_tnode **__restrict, __compar_fn_t);
void tdestroy (void *, void (*)(void *));
-void *tfind(const void *, void **, __compar_fn_t);
-void *tsearch(const void *, void **, __compar_fn_t);
-void twalk(const void *, void (*)(const void *, VISIT, int));
+posix_tnode *tfind(const void *, posix_tnode *const *, __compar_fn_t);
+posix_tnode *tsearch(const void *, posix_tnode **, __compar_fn_t);
+void twalk(const posix_tnode *, void (*)(const posix_tnode *, VISIT, int));
__END_DECLS
#endif /* !_SEARCH_H_ */
diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h
index 0690a03..55b20fa 100644
--- a/newlib/libc/include/stdlib.h
+++ b/newlib/libc/include/stdlib.h
@@ -333,10 +333,13 @@ extern long double strtold (const char *__restrict, char **__restrict);
#if __ISO_C_VISIBLE >= 2011
void * aligned_alloc(size_t, size_t) __malloc_like __alloc_align(1)
__alloc_size(2) __result_use_check;
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
+#if (__ISO_C_VISIBLE >= 2011 || __POSIX_VISIBLE >= 202405)
int at_quick_exit(void (*)(void));
_Noreturn void
quick_exit(int);
-#endif /* __ISO_C_VISIBLE >= 2011 */
+#endif /* __ISO_C_VISIBLE >= 2011 || __POSIX_VISIBLE >= 202405 */
_END_STD_C
diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h
index 5dcc77a..4c9acc5 100644
--- a/newlib/libc/include/sys/config.h
+++ b/newlib/libc/include/sys/config.h
@@ -4,7 +4,7 @@
#include <machine/ieeefp.h> /* floating point macros */
#include <sys/features.h> /* POSIX defs */
-#ifdef __aarch64__
+#if defined(__aarch64__) || defined(__mips__)
#define MALLOC_ALIGNMENT 16
#endif
diff --git a/newlib/libc/include/sys/reent.h b/newlib/libc/include/sys/reent.h
index 5ce5387..eafac96 100644
--- a/newlib/libc/include/sys/reent.h
+++ b/newlib/libc/include/sys/reent.h
@@ -709,7 +709,8 @@ struct _reent
{0, {0}}, \
{0, {0}}, \
{0, {0}}, \
- {0, {0}} \
+ {0, {0}}, \
+ 0 \
} \
}, \
_REENT_INIT_RESERVED_6_7 \
diff --git a/newlib/libc/include/sys/stat.h b/newlib/libc/include/sys/stat.h
index b4e27f2..7edfe34 100644
--- a/newlib/libc/include/sys/stat.h
+++ b/newlib/libc/include/sys/stat.h
@@ -38,6 +38,16 @@ struct stat
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
+#elif defined(__mips__)
+ time_t st_atime;
+ long st_spare1;
+ time_t st_mtime;
+ long st_spare2;
+ time_t st_ctime;
+ long st_spare3;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+ long st_spare4[2];
#else
struct timespec st_atim;
struct timespec st_mtim;
@@ -50,7 +60,7 @@ struct stat
#endif
};
-#if !(defined(__svr4__) && !defined(__PPC__) && !defined(__sun__))
+#if !((defined(__svr4__) && !defined(__PPC__) && !defined(__sun__)) || defined(__mips__))
#define st_atime st_atim.tv_sec
#define st_ctime st_ctim.tv_sec
#define st_mtime st_mtim.tv_sec
@@ -136,7 +146,11 @@ struct stat
int chmod (const char *__path, mode_t __mode );
int fchmod (int __fd, mode_t __mode);
+#if defined(__mips__) && defined(__mips16)
+int __attribute__((nomips16)) fstat (int __fd, struct stat *__sbuf );
+#else
int fstat (int __fd, struct stat *__sbuf );
+#endif // __mips__
int mkdir (const char *_path, mode_t __mode );
int mkfifo (const char *__path, mode_t __mode );
int stat (const char *__restrict __path, struct stat *__restrict __sbuf );
diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/unistd.h
index 771a4bd..4cf9f06 100644
--- a/newlib/libc/include/sys/unistd.h
+++ b/newlib/libc/include/sys/unistd.h
@@ -215,7 +215,7 @@ int setpgrp (void);
#if defined(__CYGWIN__) && __BSD_VISIBLE
/* Stub for Linux libbsd compatibility. */
#define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e))
-static inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}
+static __inline void setproctitle_init (int _c, char *_a[], char *_e[]) {}
void setproctitle (const char *, ...)
_ATTRIBUTE ((__format__ (__printf__, 1, 2)));
diff --git a/newlib/libc/include/time.h b/newlib/libc/include/time.h
index ab34913..a2df4f7 100644
--- a/newlib/libc/include/time.h
+++ b/newlib/libc/include/time.h
@@ -57,6 +57,11 @@ clock_t clock (void);
double difftime (time_t _time2, time_t _time1);
time_t mktime (struct tm *_timeptr);
time_t time (time_t *_timer);
+#if (__ISO_C_VISIBLE >= 2011 || __POSIX_VISIBLE >= 202405)
+#define TIME_UTC 1
+
+int timespec_get(struct timespec *ts, int base);
+#endif
#ifndef _REENT_ONLY
char *asctime (const struct tm *_tblock);
char *ctime (const time_t *_time);
diff --git a/newlib/libc/machine/aarch64/sys/fenv.h b/newlib/libc/machine/aarch64/sys/fenv.h
index 6b08792..1f97791 100644
--- a/newlib/libc/machine/aarch64/sys/fenv.h
+++ b/newlib/libc/machine/aarch64/sys/fenv.h
@@ -80,9 +80,17 @@ extern const fenv_t *_fe_dfl_env;
#if __BSD_VISIBLE
-/* We currently provide no external definitions of the functions below. */
+/* We currently provide no external definitions of the functions below
+ except of for Cygwin where those functions are exported by
+ winsup/cygwin/cygwin.din. */
+
+#ifdef __CYGWIN__
+#define __cygwin_fenv_static __fenv_static
+#else
+#define __cygwin_fenv_static static
+#endif
-static inline int
+__cygwin_fenv_static inline int
feenableexcept(int __mask)
{
fenv_t __old_r, __new_r;
@@ -93,7 +101,7 @@ feenableexcept(int __mask)
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}
-static inline int
+__cygwin_fenv_static inline int
fedisableexcept(int __mask)
{
fenv_t __old_r, __new_r;
@@ -104,7 +112,7 @@ fedisableexcept(int __mask)
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}
-static inline int
+__cygwin_fenv_static inline int
fegetexcept(void)
{
fenv_t __r;
diff --git a/newlib/libc/machine/mips/Makefile.inc b/newlib/libc/machine/mips/Makefile.inc
index 22f0c6e..3686beb 100644
--- a/newlib/libc/machine/mips/Makefile.inc
+++ b/newlib/libc/machine/mips/Makefile.inc
@@ -1 +1 @@
-libc_a_SOURCES += %D%/setjmp.S %D%/strlen.c %D%/strcmp.S %D%/strncpy.c %D%/memset.S %D%/memcpy.S
+libc_a_SOURCES += %D%/setjmp.S %D%/strlen.c %D%/strcmp.S %D%/strncpy.c %D%/memset.c %D%/memcpy.c
diff --git a/newlib/libc/machine/mips/machine/regdef.h b/newlib/libc/machine/mips/machine/regdef.h
index 0164164..5d19f90 100644
--- a/newlib/libc/machine/mips/machine/regdef.h
+++ b/newlib/libc/machine/mips/machine/regdef.h
@@ -45,6 +45,11 @@
#define v0 $2
#define v1 $3
+#define va0 $2
+#define va1 $3
+
+#define vt0 $2
+#define vt1 $3
#define a0 $4
#define a1 $5
@@ -100,4 +105,37 @@
#define fp $30
#define ra $31
+#define r0 $0
+#define r1 $1
+#define r2 $2
+#define r3 $3
+#define r4 $4
+#define r5 $5
+#define r6 $6
+#define r7 $7
+#define r8 $8
+#define r9 $9
+#define r10 $10
+#define r11 $11
+#define r12 $12
+#define r13 $13
+#define r14 $14
+#define r15 $15
+#define r16 $16
+#define r17 $17
+#define r18 $18
+#define r19 $19
+#define r20 $20
+#define r21 $21
+#define r22 $22
+#define r23 $23
+#define r24 $24
+#define r25 $25
+#define r26 $26
+#define r27 $27
+#define r28 $28
+#define r29 $29
+#define r30 $30
+#define r31 $31
+
#endif
diff --git a/newlib/libc/machine/mips/memcpy.c b/newlib/libc/machine/mips/memcpy.c
new file mode 100644
index 0000000..03ef299
--- /dev/null
+++ b/newlib/libc/machine/mips/memcpy.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2018 MIPS Tech, LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Typical observed latency in cycles in fetching from DRAM. */
+#ifndef LATENCY_CYCLES
+ #define LATENCY_CYCLES 63
+#endif
+
+/* Pre-fetch performance is subject to accurate prefetch ahead,
+ which in turn depends on both the cache-line size and the amount
+ of look-ahead. Since cache-line size is not nominally fixed in
+ a typically library built for multiple platforms, we make conservative
+ assumptions in the default case. This code will typically operate
+ on such conservative assumptions, but if compiled with the correct
+ -mtune=xx options, will perform even better on those specific
+ platforms. */
+#if defined(_MIPS_TUNE_OCTEON2) || defined(_MIPS_TUNE_OCTEON3)
+ #define CACHE_LINE 128
+ #define BLOCK_CYCLES 30
+ #undef LATENCY_CYCLES
+ #define LATENCY_CYCLES 150
+#elif defined(_MIPS_TUNE_I6400) || defined(_MIPS_TUNE_I6500)
+ #define CACHE_LINE 64
+ #define BLOCK_CYCLES 15
+#elif defined(_MIPS_TUNE_P6600)
+ #define CACHE_LINE 32
+ #define BLOCK_CYCLES 15
+#elif defined(_MIPS_TUNE_INTERAPTIV) || defined(_MIPS_TUNE_INTERAPTIV_MR2)
+ #define CACHE_LINE 32
+ #define BLOCK_CYCLES 30
+#else
+ #ifndef CACHE_LINE
+ #define CACHE_LINE 32
+ #endif
+ #ifndef BLOCK_CYCLES
+ #ifdef __nanomips__
+ #define BLOCK_CYCLES 20
+ #else
+ #define BLOCK_CYCLES 11
+ #endif
+ #endif
+#endif
+
+/* Pre-fetch look ahead = ceil (latency / block-cycles) */
+#define PREF_AHEAD (LATENCY_CYCLES / BLOCK_CYCLES \
+ + ((LATENCY_CYCLES % BLOCK_CYCLES) == 0 ? 0 : 1))
+
+/* The unroll-factor controls how many words at a time in the core loop. */
+#ifndef BLOCK_SIZE
+ #define BLOCK_SIZE (CACHE_LINE == 128 ? 16 : 8)
+#elif BLOCK_SIZE != 8 && BLOCK_SIZE != 16
+ #error "BLOCK_SIZE must be 8 or 16"
+#endif
+
+#define __overloadable
+#if !defined(UNALIGNED_INSTR_SUPPORT)
+/* does target have unaligned lw/ld/ualw/uald instructions? */
+ #define UNALIGNED_INSTR_SUPPORT 0
+#if (__mips_isa_rev < 6 && !defined(__mips1)) || defined(__nanomips__)
+ #undef UNALIGNED_INSTR_SUPPORT
+ #define UNALIGNED_INSTR_SUPPORT 1
+ #endif
+#endif
+#if !defined(HW_UNALIGNED_SUPPORT)
+/* Does target have hardware support for unaligned accesses? */
+ #define HW_UNALIGNED_SUPPORT 0
+ #if __mips_isa_rev >= 6 && !defined(__nanomips__)
+ #undef HW_UNALIGNED_SUPPORT
+ #define HW_UNALIGNED_SUPPORT 1
+ #endif
+#endif
+
+#ifndef ENABLE_PREFETCH
+ #define ENABLE_PREFETCH 1
+#endif
+
+#ifndef ENABLE_PREFETCH_CHECK
+ #define ENABLE_PREFETCH_CHECK 0
+#endif
+
+#if ENABLE_PREFETCH
+ #if ENABLE_PREFETCH_CHECK
+#include <assert.h>
+static char *limit;
+#define PREFETCH(addr) \
+ do { \
+ assert ((char *)(addr) < limit); \
+ __builtin_prefetch ((addr), 0, 1); \
+ } while (0)
+#else /* ENABLE_PREFETCH_CHECK */
+ #define PREFETCH(addr) __builtin_prefetch (addr, 0, 1)
+ #endif /* ENABLE_PREFETCH_CHECK */
+#else /* ENABLE_PREFETCH */
+ #define PREFETCH(addr)
+#endif /* ENABLE_PREFETCH */
+
+#include <string.h>
+
+#ifdef __mips64
+typedef unsigned long long reg_t;
+typedef struct
+{
+ reg_t B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8;
+} bits_t;
+#else /* __mips64 */
+typedef unsigned long reg_t;
+typedef struct
+{
+ reg_t B0:8, B1:8, B2:8, B3:8;
+} bits_t;
+#endif /* __mips64 */
+
+#define CACHE_LINES_PER_BLOCK \
+ ((BLOCK_SIZE * sizeof (reg_t) > CACHE_LINE) \
+ ? (BLOCK_SIZE * sizeof (reg_t) / CACHE_LINE) \
+ : 1)
+
+typedef union
+{
+ reg_t v;
+ bits_t b;
+} bitfields_t;
+
+#define DO_BYTE(a, i) \
+ a[i] = bw.b.B##i; \
+ len--; \
+ if (!len) return ret; \
+
+/* This code is called when aligning a pointer, there are remaining bytes
+ after doing word compares, or architecture does not have some form
+ of unaligned support. */
+static inline void * __attribute__ ((always_inline))
+do_bytes (void *a, const void *b, unsigned long len, void *ret)
+{
+ unsigned char *x = (unsigned char *) a;
+ unsigned char *y = (unsigned char *) b;
+ unsigned long i;
+ /* 'len' might be zero here, so preloading the first two values
+ before the loop may access unallocated memory. */
+ for (i = 0; i < len; i++)
+ {
+ *x = *y;
+ x++;
+ y++;
+ }
+ return ret;
+}
+
+/* This code is called to copy only remaining bytes within word or doubleword */
+static inline void * __attribute__ ((always_inline))
+do_bytes_remaining (void *a, const void *b, unsigned long len, void *ret)
+{
+ unsigned char *x = (unsigned char *) a;
+ bitfields_t bw;
+ if (len > 0)
+ {
+ bw.v = *(reg_t *)b;
+ DO_BYTE(x, 0);
+ DO_BYTE(x, 1);
+ DO_BYTE(x, 2);
+#ifdef __mips64
+ DO_BYTE(x, 3);
+ DO_BYTE(x, 4);
+ DO_BYTE(x, 5);
+ DO_BYTE(x, 6);
+#endif /* __mips64 */
+ }
+ return ret;
+}
+
+static inline void * __attribute__ ((always_inline))
+do_words_remaining (reg_t *a, const reg_t *b, unsigned long words,
+ unsigned long bytes, void *ret)
+{
+ /* Use a set-back so that load/stores have incremented addresses in
+ order to promote bonding. */
+ int off = (BLOCK_SIZE - words);
+ a -= off;
+ b -= off;
+ switch (off)
+ {
+ case 1: a[1] = b[1];
+ case 2: a[2] = b[2];
+ case 3: a[3] = b[3];
+ case 4: a[4] = b[4];
+ case 5: a[5] = b[5];
+ case 6: a[6] = b[6];
+ case 7: a[7] = b[7];
+#if BLOCK_SIZE==16
+ case 8: a[8] = b[8];
+ case 9: a[9] = b[9];
+ case 10: a[10] = b[10];
+ case 11: a[11] = b[11];
+ case 12: a[12] = b[12];
+ case 13: a[13] = b[13];
+ case 14: a[14] = b[14];
+ case 15: a[15] = b[15];
+#endif /* BLOCK_SIZE==16 */
+ }
+ return do_bytes_remaining (a + BLOCK_SIZE, b + BLOCK_SIZE, bytes, ret);
+}
+
+#if !HW_UNALIGNED_SUPPORT
+#if UNALIGNED_INSTR_SUPPORT
+/* For MIPS GCC, there are no unaligned builtins - so this struct forces
+ the compiler to treat the pointer access as unaligned. */
+struct ulw
+{
+ reg_t uli;
+} __attribute__ ((packed));
+static inline void * __attribute__ ((always_inline))
+do_uwords_remaining (struct ulw *a, const reg_t *b, unsigned long words,
+ unsigned long bytes, void *ret)
+{
+ /* Use a set-back so that load/stores have incremented addresses in
+ order to promote bonding. */
+ int off = (BLOCK_SIZE - words);
+ a -= off;
+ b -= off;
+ switch (off)
+ {
+ case 1: a[1].uli = b[1];
+ case 2: a[2].uli = b[2];
+ case 3: a[3].uli = b[3];
+ case 4: a[4].uli = b[4];
+ case 5: a[5].uli = b[5];
+ case 6: a[6].uli = b[6];
+ case 7: a[7].uli = b[7];
+#if BLOCK_SIZE==16
+ case 8: a[8].uli = b[8];
+ case 9: a[9].uli = b[9];
+ case 10: a[10].uli = b[10];
+ case 11: a[11].uli = b[11];
+ case 12: a[12].uli = b[12];
+ case 13: a[13].uli = b[13];
+ case 14: a[14].uli = b[14];
+ case 15: a[15].uli = b[15];
+#endif /* BLOCK_SIZE==16 */
+ }
+ return do_bytes_remaining (a + BLOCK_SIZE, b + BLOCK_SIZE, bytes, ret);
+}
+
+/* The first pointer is not aligned while second pointer is. */
+static void *
+unaligned_words (struct ulw *a, const reg_t * b,
+ unsigned long words, unsigned long bytes, void *ret)
+{
+ unsigned long i, words_by_block, words_by_1;
+ words_by_1 = words % BLOCK_SIZE;
+ words_by_block = words / BLOCK_SIZE;
+
+ for (; words_by_block > 0; words_by_block--)
+ {
+ /* This condition is deliberately conservative. One could theoretically
+ pre-fetch another time around in some cases without crossing the page
+ boundary at the limit, but checking for the right conditions here is
+ too expensive to be worth it. */
+ if (words_by_block > PREF_AHEAD)
+ for (i = 0; i < CACHE_LINES_PER_BLOCK; i++)
+ PREFETCH (b + ((BLOCK_SIZE / CACHE_LINES_PER_BLOCK)
+ * (PREF_AHEAD + i)));
+
+ reg_t y0 = b[0], y1 = b[1], y2 = b[2], y3 = b[3];
+ reg_t y4 = b[4], y5 = b[5], y6 = b[6], y7 = b[7];
+ a[0].uli = y0;
+ a[1].uli = y1;
+ a[2].uli = y2;
+ a[3].uli = y3;
+ a[4].uli = y4;
+ a[5].uli = y5;
+ a[6].uli = y6;
+ a[7].uli = y7;
+#if BLOCK_SIZE==16
+ y0 = b[8], y1 = b[9], y2 = b[10], y3 = b[11];
+ y4 = b[12], y5 = b[13], y6 = b[14], y7 = b[15];
+ a[8].uli = y0;
+ a[9].uli = y1;
+ a[10].uli = y2;
+ a[11].uli = y3;
+ a[12].uli = y4;
+ a[13].uli = y5;
+ a[14].uli = y6;
+ a[15].uli = y7;
+#endif /* BLOCK_SIZE==16 */
+ a += BLOCK_SIZE;
+ b += BLOCK_SIZE;
+ }
+
+ /* Mop up any remaining bytes. */
+ return do_uwords_remaining (a, b, words_by_1, bytes, ret);
+}
+
+#else /* !UNALIGNED_INSTR_SUPPORT */
+
+/* No HW support or unaligned lw/ld/ualw/uald instructions. */
+static void *
+unaligned_words (reg_t * a, const reg_t * b,
+ unsigned long words, unsigned long bytes, void *ret)
+{
+ unsigned long i;
+ unsigned char *x;
+ for (i = 0; i < words; i++)
+ {
+ bitfields_t bw;
+ bw.v = *((reg_t*) b);
+ x = (unsigned char *) a;
+ x[0] = bw.b.B0;
+ x[1] = bw.b.B1;
+ x[2] = bw.b.B2;
+ x[3] = bw.b.B3;
+#ifdef __mips64
+ x[4] = bw.b.B4;
+ x[5] = bw.b.B5;
+ x[6] = bw.b.B6;
+ x[7] = bw.b.B7;
+#endif
+ a += 1;
+ b += 1;
+ }
+ /* Mop up any remaining bytes. */
+ return do_bytes_remaining (a, b, bytes, ret);
+}
+
+#endif /* UNALIGNED_INSTR_SUPPORT */
+#endif /* HW_UNALIGNED_SUPPORT */
+
+/* both pointers are aligned, or first isn't and HW support for unaligned. */
+static void *
+aligned_words (reg_t * a, const reg_t * b,
+ unsigned long words, unsigned long bytes, void *ret)
+{
+ unsigned long i, words_by_block, words_by_1;
+ words_by_1 = words % BLOCK_SIZE;
+ words_by_block = words / BLOCK_SIZE;
+
+ for (; words_by_block > 0; words_by_block--)
+ {
+ if (words_by_block > PREF_AHEAD)
+ for (i = 0; i < CACHE_LINES_PER_BLOCK; i++)
+ PREFETCH (b + ((BLOCK_SIZE / CACHE_LINES_PER_BLOCK)
+ * (PREF_AHEAD + i)));
+
+ reg_t x0 = b[0], x1 = b[1], x2 = b[2], x3 = b[3];
+ reg_t x4 = b[4], x5 = b[5], x6 = b[6], x7 = b[7];
+ a[0] = x0;
+ a[1] = x1;
+ a[2] = x2;
+ a[3] = x3;
+ a[4] = x4;
+ a[5] = x5;
+ a[6] = x6;
+ a[7] = x7;
+#if BLOCK_SIZE==16
+ x0 = b[8], x1 = b[9], x2 = b[10], x3 = b[11];
+ x4 = b[12], x5 = b[13], x6 = b[14], x7 = b[15];
+ a[8] = x0;
+ a[9] = x1;
+ a[10] = x2;
+ a[11] = x3;
+ a[12] = x4;
+ a[13] = x5;
+ a[14] = x6;
+ a[15] = x7;
+#endif /* BLOCK_SIZE==16 */
+ a += BLOCK_SIZE;
+ b += BLOCK_SIZE;
+ }
+
+ /* mop up any remaining bytes. */
+ return do_words_remaining (a, b, words_by_1, bytes, ret);
+}
+
+void *
+memcpy (void *a, const void *b, size_t len) __overloadable
+{
+ unsigned long bytes, words, i;
+ void *ret = a;
+#if ENABLE_PREFETCH_CHECK
+ limit = (char *)b + len;
+#endif /* ENABLE_PREFETCH_CHECK */
+ /* shouldn't hit that often. */
+ if (len <= 8)
+ return do_bytes (a, b, len, a);
+
+ /* Start pre-fetches ahead of time. */
+ if (len > CACHE_LINE * PREF_AHEAD)
+ for (i = 1; i < PREF_AHEAD; i++)
+ PREFETCH ((char *)b + CACHE_LINE * i);
+ else
+ for (i = 1; i < len / CACHE_LINE; i++)
+ PREFETCH ((char *)b + CACHE_LINE * i);
+
+ /* Align the second pointer to word/dword alignment.
+ Note that the pointer is only 32-bits for o32/n32 ABIs. For
+ n32, loads are done as 64-bit while address remains 32-bit. */
+ bytes = ((unsigned long) b) % (sizeof (reg_t));
+
+ if (bytes)
+ {
+ bytes = (sizeof (reg_t)) - bytes;
+ if (bytes > len)
+ bytes = len;
+ do_bytes (a, b, bytes, ret);
+ if (len == bytes)
+ return ret;
+ len -= bytes;
+ a = (void *) (((unsigned char *) a) + bytes);
+ b = (const void *) (((unsigned char *) b) + bytes);
+ }
+
+ /* Second pointer now aligned. */
+ words = len / sizeof (reg_t);
+ bytes = len % sizeof (reg_t);
+
+#if HW_UNALIGNED_SUPPORT
+ /* treat possible unaligned first pointer as aligned. */
+ return aligned_words (a, b, words, bytes, ret);
+#else /* !HW_UNALIGNED_SUPPORT */
+ if (((unsigned long) a) % sizeof (reg_t) == 0)
+ return aligned_words (a, b, words, bytes, ret);
+ /* need to use unaligned instructions on first pointer. */
+ return unaligned_words (a, b, words, bytes, ret);
+#endif /* HW_UNALIGNED_SUPPORT */
+}
diff --git a/newlib/libc/machine/mips/memset.c b/newlib/libc/machine/mips/memset.c
new file mode 100644
index 0000000..9f07ef5
--- /dev/null
+++ b/newlib/libc/machine/mips/memset.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 MIPS Tech, LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+
+#if _MIPS_SIM == _ABIO32
+#define SIZEOF_reg_t 4
+typedef unsigned long reg_t;
+#else
+#define SIZEOF_reg_t 8
+typedef unsigned long long reg_t;
+#endif
+
+typedef struct bits8
+{
+ reg_t B0:8, B1:8, B2:8, B3:8;
+#if SIZEOF_reg_t == 8
+ reg_t B4:8, B5:8, B6:8, B7:8;
+#endif
+} bits8_t;
+typedef struct bits16
+{
+ reg_t B0:16, B1:16;
+#if SIZEOF_reg_t == 8
+ reg_t B2:16, B3:16;
+#endif
+} bits16_t;
+typedef struct bits32
+{
+ reg_t B0:32;
+#if SIZEOF_reg_t == 8
+ reg_t B1:32;
+#endif
+} bits32_t;
+
+/* This union assumes that small structures can be in registers. If
+ not, then memory accesses will be done - not optimal, but ok. */
+typedef union
+{
+ reg_t v;
+ bits8_t b8;
+ bits16_t b16;
+ bits32_t b32;
+} bitfields_t;
+
+/* This code is called when aligning a pointer or there are remaining bytes
+ after doing word sets. */
+static inline void * __attribute__ ((always_inline))
+do_bytes (void *a, void *retval, unsigned char fill, const unsigned long len)
+{
+ unsigned char *x = ((unsigned char *) a);
+ unsigned long i;
+
+ for (i = 0; i < len; i++)
+ *x++ = fill;
+
+ return retval;
+}
+
+/* Pointer is aligned. */
+static void *
+do_aligned_words (reg_t * a, void * retval, reg_t fill,
+ unsigned long words, unsigned long bytes)
+{
+ unsigned long i, words_by_1, words_by_16;
+
+ words_by_1 = words % 16;
+ words_by_16 = words / 16;
+
+ /*
+ * Note: prefetching the store memory is not beneficial on most
+ * cores since the ls/st unit has store buffers that will be filled
+ * before the cache line is actually needed.
+ *
+ * Also, using prepare-for-store cache op is problematic since we
+ * don't know the implementation-defined cache line length and we
+ * don't want to touch unintended memory.
+ */
+ for (i = 0; i < words_by_16; i++)
+ {
+ a[0] = fill;
+ a[1] = fill;
+ a[2] = fill;
+ a[3] = fill;
+ a[4] = fill;
+ a[5] = fill;
+ a[6] = fill;
+ a[7] = fill;
+ a[8] = fill;
+ a[9] = fill;
+ a[10] = fill;
+ a[11] = fill;
+ a[12] = fill;
+ a[13] = fill;
+ a[14] = fill;
+ a[15] = fill;
+ a += 16;
+ }
+
+ /* do remaining words. */
+ for (i = 0; i < words_by_1; i++)
+ *a++ = fill;
+
+ /* mop up any remaining bytes. */
+ return do_bytes (a, retval, fill, bytes);
+}
+
+void *
+memset (void *a, int ifill, size_t len)
+{
+ unsigned long bytes, words;
+ bitfields_t fill;
+ void *retval = (void *) a;
+
+ /* shouldn't hit that often. */
+ if (len < 16)
+ return do_bytes (a, retval, ifill, len);
+
+ /* Align the pointer to word/dword alignment.
+ Note that the pointer is only 32-bits for o32/n32 ABIs. For
+ n32, loads are done as 64-bit while address remains 32-bit. */
+ bytes = ((unsigned long) a) % (sizeof (reg_t) * 2);
+ if (bytes)
+ {
+ bytes = (sizeof (reg_t) * 2 - bytes);
+ if (bytes > len)
+ bytes = len;
+ do_bytes (a, retval, ifill, bytes);
+ if (len == bytes)
+ return retval;
+ len -= bytes;
+ a = (void *) (((unsigned char *) a) + bytes);
+ }
+
+ /* Create correct fill value for reg_t sized variable. */
+ if (ifill != 0)
+ {
+ fill.b8.B0 = (unsigned char) ifill;
+ fill.b8.B1 = fill.b8.B0;
+ fill.b16.B1 = fill.b16.B0;
+#if SIZEOF_reg_t == 8
+ fill.b32.B1 = fill.b32.B0;
+#endif
+ }
+ else
+ fill.v = 0;
+
+ words = len / sizeof (reg_t);
+ bytes = len % sizeof (reg_t);
+ return do_aligned_words (a, retval, fill.v, words, bytes);
+}
diff --git a/newlib/libc/machine/mips/setjmp.S b/newlib/libc/machine/mips/setjmp.S
index cfc1d51..1e3ee0d 100644
--- a/newlib/libc/machine/mips/setjmp.S
+++ b/newlib/libc/machine/mips/setjmp.S
@@ -67,7 +67,7 @@
regardless of whether the realignment happened or not. */
#define FPR_LAYOUT \
- and $8, $4, 4; \
+ andi $8, $4, 4; \
beq $8, $0, 1f; \
GPR_OFFSET ($31, 22); \
addiu $4, $4, -4; \
@@ -133,7 +133,7 @@ setjmp:
#undef FPR_OFFSET
move $2,$0
- j $31
+ jr $31
.end setjmp
@@ -154,6 +154,6 @@ longjmp:
li $5,1
1:
move $2,$5
- j $31
+ jr $31
.end longjmp
diff --git a/newlib/libc/machine/mips/strcmp.S b/newlib/libc/machine/mips/strcmp.S
index 9d33a4e..07b988a 100644
--- a/newlib/libc/machine/mips/strcmp.S
+++ b/newlib/libc/machine/mips/strcmp.S
@@ -1,31 +1,30 @@
/*
- * Copyright (c) 2014
- * Imagination Technologies Limited.
+ * Copyright (C) 2014-2018 MIPS Tech, LLC
*
* Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * modification, are permitted provided that the following conditions are met:
*
- * THIS SOFTWARE IS PROVIDED BY IMAGINATION TECHNOLOGIES LIMITED ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL IMAGINATION TECHNOLOGIES LIMITED BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+*/
#ifdef ANDROID_CHANGES
# include "machine/asm.h"
@@ -38,22 +37,14 @@
# include <sys/asm.h>
#endif
-/* Technically strcmp should not read past the end of the strings being
- compared. We will read a full word that may contain excess bits beyond
- the NULL string terminator but unless ENABLE_READAHEAD is set, we will not
- read the next word after the end of string. Setting ENABLE_READAHEAD will
- improve performance but is technically illegal based on the definition of
- strcmp. */
-#ifdef ENABLE_READAHEAD
-# define DELAY_READ
-#else
-# define DELAY_READ nop
-#endif
-
/* Testing on a little endian machine showed using CLZ was a
performance loss, so we are not turning it on by default. */
#if defined(ENABLE_CLZ) && (__mips_isa_rev > 1)
# define USE_CLZ
+#elif (__mips_isa_rev >= 2)
+# define USE_EXT 1
+#else
+# define USE_EXT 0
#endif
/* Some asm.h files do not have the L macro definition. */
@@ -74,6 +65,10 @@
# endif
#endif
+/* Haven't yet found a configuration where DSP code outperforms
+ normal assembly. */
+#define __mips_using_dsp 0
+
/* Allow the routine to be named something else if desired. */
#ifndef STRCMP_NAME
# define STRCMP_NAME strcmp
@@ -85,148 +80,184 @@ LEAF(STRCMP_NAME, 0)
LEAF(STRCMP_NAME)
#endif
.set nomips16
- .set noreorder
-
or t0, a0, a1
- andi t0,0x3
+ andi t0, t0, 0x3
bne t0, zero, L(byteloop)
/* Both strings are 4 byte aligned at this point. */
- lui t8, 0x0101
- ori t8, t8, 0x0101
- lui t9, 0x7f7f
- ori t9, 0x7f7f
-
-#define STRCMP32(OFFSET) \
- lw v0, OFFSET(a0); \
- lw v1, OFFSET(a1); \
- subu t0, v0, t8; \
- bne v0, v1, L(worddiff); \
- nor t1, v0, t9; \
- and t0, t0, t1; \
+ li t8, 0x01010101
+#if !__mips_using_dsp
+ li t9, 0x7f7f7f7f
+#endif
+
+#if __mips_using_dsp
+# define STRCMP32(OFFSET) \
+ lw a2, OFFSET(a0); \
+ lw a3, OFFSET(a1); \
+ subu_s.qb t0, t8, a2; \
+ bne a2, a3, L(worddiff); \
bne t0, zero, L(returnzero)
+#else /* !__mips_using_dsp */
+# define STRCMP32(OFFSET) \
+ lw a2, OFFSET(a0); \
+ lw a3, OFFSET(a1); \
+ subu t0, a2, t8; \
+ nor t1, a2, t9; \
+ bne a2, a3, L(worddiff); \
+ and t1, t0, t1; \
+ bne t1, zero, L(returnzero)
+#endif /* __mips_using_dsp */
+ .align 2
L(wordloop):
STRCMP32(0)
- DELAY_READ
STRCMP32(4)
- DELAY_READ
STRCMP32(8)
- DELAY_READ
STRCMP32(12)
- DELAY_READ
STRCMP32(16)
- DELAY_READ
STRCMP32(20)
- DELAY_READ
STRCMP32(24)
- DELAY_READ
- STRCMP32(28)
+ lw a2, 28(a0)
+ lw a3, 28(a1)
+#if __mips_using_dsp
+ subu_s.qb t0, t8, a2
+#else
+ subu t0, a2, t8
+ nor t1, a2, t9
+ and t1, t0, t1
+#endif
+
PTR_ADDIU a0, a0, 32
- b L(wordloop)
+ bne a2, a3, L(worddiff)
PTR_ADDIU a1, a1, 32
+ beq t1, zero, L(wordloop)
L(returnzero):
- j ra
- move v0, zero
+ move va0, zero
+ jr ra
+ .align 2
L(worddiff):
#ifdef USE_CLZ
- subu t0, v0, t8
- nor t1, v0, t9
- and t1, t0, t1
- xor t0, v0, v1
+ xor t0, a2, a3
or t0, t0, t1
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
wsbh t0, t0
rotr t0, t0, 16
-# endif
+# endif /* LITTLE_ENDIAN */
clz t1, t0
- and t1, 0xf8
-# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- neg t1
- addu t1, 24
+ or t0, t1, 24 /* Only care about multiples of 8. */
+ xor t1, t1, t0 /* {0,8,16,24} => {24,16,8,0} */
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ sllv a2,a2,t1
+ sllv a3,a3,t1
+# else
+ srlv a2,a2,t1
+ srlv a3,a3,t1
# endif
- rotrv v0, v0, t1
- rotrv v1, v1, t1
- and v0, v0, 0xff
- and v1, v1, 0xff
- j ra
- subu v0, v0, v1
+ subu va0, a2, a3
+ jr ra
#else /* USE_CLZ */
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- andi t0, v0, 0xff
- beq t0, zero, L(wexit01)
- andi t1, v1, 0xff
- bne t0, t1, L(wexit01)
-
- srl t8, v0, 8
- srl t9, v1, 8
- andi t8, t8, 0xff
+ andi a0, a2, 0xff /* abcd => d */
+ andi a1, a3, 0xff
+ beq a0, zero, L(wexit01)
+# if USE_EXT
+ ext t8, a2, 8, 8
+ bne a0, a1, L(wexit01)
+ ext t9, a3, 8, 8
beq t8, zero, L(wexit89)
+ ext a0, a2, 16, 8
+ bne t8, t9, L(wexit89)
+ ext a1, a3, 16, 8
+# else /* !USE_EXT */
+ srl t8, a2, 8
+ bne a0, a1, L(wexit01)
+ srl t9, a3, 8
+ andi t8, t8, 0xff
andi t9, t9, 0xff
+ beq t8, zero, L(wexit89)
+ srl a0, a2, 16
bne t8, t9, L(wexit89)
+ srl a1, a3, 16
+ andi a0, a0, 0xff
+ andi a1, a1, 0xff
+# endif /* !USE_EXT */
- srl t0, v0, 16
- srl t1, v1, 16
- andi t0, t0, 0xff
- beq t0, zero, L(wexit01)
- andi t1, t1, 0xff
- bne t0, t1, L(wexit01)
-
- srl t8, v0, 24
- srl t9, v1, 24
# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
- srl t0, v0, 24
- beq t0, zero, L(wexit01)
- srl t1, v1, 24
- bne t0, t1, L(wexit01)
+ srl a0, a2, 24 /* abcd => a */
+ srl a1, a3, 24
+ beq a0, zero, L(wexit01)
- srl t8, v0, 16
- srl t9, v1, 16
- andi t8, t8, 0xff
+# if USE_EXT
+ ext t8, a2, 16, 8
+ bne a0, a1, L(wexit01)
+ ext t9, a3, 16, 8
beq t8, zero, L(wexit89)
+ ext a0, a2, 8, 8
+ bne t8, t9, L(wexit89)
+ ext a1, a3, 8, 8
+# else /* ! USE_EXT */
+ srl t8, a2, 16
+ bne a0, a1, L(wexit01)
+ srl t9, a3, 16
+ andi t8, t8, 0xff
andi t9, t9, 0xff
+ beq t8, zero, L(wexit89)
+ srl a0, a2, 8
bne t8, t9, L(wexit89)
+ srl a1, a3, 8
+ andi a0, a0, 0xff
+ andi a1, a1, 0xff
+# endif /* USE_EXT */
+
+# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
- srl t0, v0, 8
- srl t1, v1, 8
- andi t0, t0, 0xff
- beq t0, zero, L(wexit01)
- andi t1, t1, 0xff
- bne t0, t1, L(wexit01)
+ beq a0, zero, L(wexit01)
+ bne a0, a1, L(wexit01)
- andi t8, v0, 0xff
- andi t9, v1, 0xff
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ srl a0, a2, 24
+ srl a1, a3, 24
+# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
+ move a0, a2
+ move a1, a3
# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
-L(wexit89):
- j ra
- subu v0, t8, t9
L(wexit01):
- j ra
- subu v0, t0, t1
+ subu va0, a0, a1
+ jr ra
+
+L(wexit89):
+ subu va0, t8, t9
+ jr ra
+
#endif /* USE_CLZ */
+#define DELAY_NOP nop
+
/* It might seem better to do the 'beq' instruction between the two 'lbu'
instructions so that the nop is not needed but testing showed that this
code is actually faster (based on glibc strcmp test). */
+
#define BYTECMP01(OFFSET) \
- lbu v0, OFFSET(a0); \
- lbu v1, OFFSET(a1); \
- beq v0, zero, L(bexit01); \
- nop; \
- bne v0, v1, L(bexit01)
+ lbu a3, OFFSET(a1); \
+ DELAY_NOP; \
+ beq a2, zero, L(bexit01); \
+ lbu t8, OFFSET+1(a0); \
+ bne a2, a3, L(bexit01)
#define BYTECMP89(OFFSET) \
- lbu t8, OFFSET(a0); \
lbu t9, OFFSET(a1); \
+ DELAY_NOP; \
beq t8, zero, L(bexit89); \
- nop; \
+ lbu a2, OFFSET+1(a0); \
bne t8, t9, L(bexit89)
+ .align 2
L(byteloop):
+ lbu a2, 0(a0)
BYTECMP01(0)
BYTECMP89(1)
BYTECMP01(2)
@@ -234,19 +265,21 @@ L(byteloop):
BYTECMP01(4)
BYTECMP89(5)
BYTECMP01(6)
- BYTECMP89(7)
+ lbu t9, 7(a1)
+
PTR_ADDIU a0, a0, 8
- b L(byteloop)
+ beq t8, zero, L(bexit89)
PTR_ADDIU a1, a1, 8
+ beq t8, t9, L(byteloop)
-L(bexit01):
- j ra
- subu v0, v0, v1
L(bexit89):
- j ra
- subu v0, t8, t9
+ subu va0, t8, t9
+ jr ra
+
+L(bexit01):
+ subu va0, a2, a3
+ jr ra
.set at
- .set reorder
END(STRCMP_NAME)
diff --git a/newlib/libc/machine/mips/strlen.c b/newlib/libc/machine/mips/strlen.c
index a87bddd..65cbaf3 100644
--- a/newlib/libc/machine/mips/strlen.c
+++ b/newlib/libc/machine/mips/strlen.c
@@ -33,27 +33,21 @@ strlen (const char *str)
}
#elif defined(__mips64)
__asm__("" /* 64-bit MIPS targets */
- " .set noreorder\n"
- " .set nomacro\n"
" .globl strlen\n"
" .ent strlen\n"
"strlen:\n"
" daddiu $2,$4,1\n"
"\n"
"1: lbu $3,0($4)\n"
- " bnez $3,1b\n"
" daddiu $4,$4,1\n"
+ " bnez $3,1b\n"
"\n"
- " jr $31\n"
" dsubu $2,$4,$2\n"
- " .end strlen\n"
- " .set macro\n"
- " .set reorder\n");
+ " jr $31\n"
+ " .end strlen\n");
#else
__asm__("" /* 32-bit MIPS targets */
- " .set noreorder\n"
- " .set nomacro\n"
" .globl strlen\n"
" .ent strlen\n"
"strlen:\n"
@@ -63,12 +57,10 @@ __asm__("" /* 32-bit MIPS targets */
#if defined(_R3000)
" nop \n"
#endif
- " bnez $3,1b\n"
" addiu $4,$4,1\n"
+ " bnez $3,1b\n"
"\n"
- " jr $31\n"
" subu $2,$4,$2\n"
- " .end strlen\n"
- " .set macro\n"
- " .set reorder\n");
+ " jr $31\n"
+ " .end strlen\n");
#endif
diff --git a/newlib/libc/machine/riscv/Makefile.inc b/newlib/libc/machine/riscv/Makefile.inc
index 4d6c046..85bed91 100644
--- a/newlib/libc/machine/riscv/Makefile.inc
+++ b/newlib/libc/machine/riscv/Makefile.inc
@@ -1,3 +1,3 @@
libc_a_SOURCES += \
%D%/memmove.S %D%/memmove-stub.c %D%/memset.S %D%/memcpy-asm.S %D%/memcpy.c %D%/strlen.c \
- %D%/strcpy.c %D%/stpcpy.c %D%/strcmp.S %D%/setjmp.S %D%/ieeefp.c %D%/ffs.c
+ %D%/strcpy.c %D%/stpcpy.c %D%/strcmp.S %D%/memchr.c %D%/memrchr.c %D%/setjmp.S %D%/ieeefp.c %D%/ffs.c
diff --git a/newlib/libc/machine/riscv/memchr.c b/newlib/libc/machine/riscv/memchr.c
new file mode 100644
index 0000000..62a7d19
--- /dev/null
+++ b/newlib/libc/machine/riscv/memchr.c
@@ -0,0 +1,152 @@
+/*
+FUNCTION
+ <<memchr>>---find character in memory
+
+INDEX
+ memchr
+
+SYNOPSIS
+ #include <string.h>
+ void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>);
+
+DESCRIPTION
+ This function searches memory starting at <<*<[src]>>> for the
+ character <[c]>. The search only ends with the first
+ occurrence of <[c]>, or after <[length]> characters; in
+ particular, <<NUL>> does not terminate the search.
+
+RETURNS
+ If the character <[c]> is found within <[length]> characters
+ of <<*<[src]>>>, a pointer to the character is returned. If
+ <[c]> is not found, then <<NULL>> is returned.
+
+PORTABILITY
+<<memchr>> is ANSI C.
+
+<<memchr>> requires no supporting OS subroutines.
+
+QUICKREF
+ memchr ansi pure
+*/
+
+#include <sys/asm.h>
+#include <stddef.h>
+#include "rv_string.h"
+
+// Move size
+#if __riscv_zilsd
+#define MV_SZ 8
+#else
+#define MV_SZ SZREG
+#endif
+
+
+void *
+memchr (const void *src_void,
+ int c,
+ size_t length)
+{
+ const unsigned char *src = (const unsigned char *) src_void;
+ unsigned char d = c;
+
+#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
+ size_t align = (uintptr_t) src & (MV_SZ - 1);
+
+ if (align)
+ {
+ align = MV_SZ - align;
+
+ if (length < align) align = length;
+
+ switch (align)
+ {
+#if MV_SZ == 8
+ case 7:
+ if (*src++ == d) return (void *) (src - 1);
+ case 6:
+ if (*src++ == d) return (void *) (src - 1);
+ case 5:
+ if (*src++ == d) return (void *) (src - 1);
+ case 4:
+ if (*src++ == d) return (void *) (src - 1);
+#endif /* MV_SZ == 8 */
+ case 3:
+ if (*src++ == d) return (void *) (src - 1);
+ case 2:
+ if (*src++ == d) return (void *) (src - 1);
+ case 1:
+ if (*src++ == d) return (void *) (src - 1);
+ }
+
+ length -= align;
+ }
+
+ const unsigned char *end_addr = src + (length & ~(MV_SZ - 1));
+
+ if (src < end_addr)
+ {
+ uintxlen_t mask = __libc_splat_byte(d);
+
+ do
+ {
+ uintlslen_t val = *(uintlslen_t*) src;
+ uintxlen_t word1 = val ^ mask;
+
+ if (__libc_detect_null(word1))
+ {
+#if __riscv_zbb
+ word1 = ~__LIBC_RISCV_ZBB_ORC_B(word1);
+ word1 = __LIBC_RISCV_ZBB_CNT_Z(word1);
+
+ return (void *) (src + (word1 >> 3));
+#else /* not __riscv_zbb */
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+#if __riscv_xlen == 64
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+#endif /* __riscv_xlen == 64 */
+ return (void *) src;
+#endif /* __riscv_zbb */
+ }
+#if __riscv_zilsd
+ uintxlen_t word2 = (val >> 32);
+ word2 ^= mask;
+
+ if (__libc_detect_null(word2))
+ {
+ src += MV_SZ / 2;
+#if __riscv_zbb
+ word2 = ~__LIBC_RISCV_ZBB_ORC_B(word2);
+ word2 = __LIBC_RISCV_ZBB_CNT_Z(word2);
+
+ return (void *) (src + (word2 >> 3));
+#else /* not __riscv_zbb */
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+ if (*src++ == d) return (void *) (src - 1);
+ return (void *) src;
+#endif /* __riscv_zbb */
+ }
+#endif /* __riscv_zilsd */
+
+ src += MV_SZ;
+ } while (src < end_addr);
+
+ length &= MV_SZ - 1;
+ }
+
+#endif /* not PREFER_SIZE_OVER_SPEED */
+
+ while (length--)
+ {
+ if (*src == d)
+ return (void *) src;
+ src++;
+ }
+
+ return NULL;
+}
diff --git a/newlib/libc/machine/riscv/memcpy-asm.S b/newlib/libc/machine/riscv/memcpy-asm.S
index 5571e47..2771285 100644
--- a/newlib/libc/machine/riscv/memcpy-asm.S
+++ b/newlib/libc/machine/riscv/memcpy-asm.S
@@ -14,15 +14,15 @@
.global memcpy
.type memcpy, @function
memcpy:
- mv t1, a0
+ mv a3, a0
beqz a2, 2f
1:
- lb t2, 0(a1)
- sb t2, 0(t1)
- add a2, a2, -1
- add t1, t1, 1
- add a1, a1, 1
+ lbu a4, 0(a1)
+ sb a4, 0(a3)
+ addi a2, a2, -1
+ addi a3, a3, 1
+ addi a1, a1, 1
bnez a2, 1b
2:
diff --git a/newlib/libc/machine/riscv/memcpy.c b/newlib/libc/machine/riscv/memcpy.c
index e1a34a8..a27e0ec 100644
--- a/newlib/libc/machine/riscv/memcpy.c
+++ b/newlib/libc/machine/riscv/memcpy.c
@@ -1,4 +1,5 @@
/* Copyright (c) 2017 SiFive Inc. All rights reserved.
+ Copyright (c) 2025 Mahmoud Abumandour <ma.mandourr@gmail.com>
This copyrighted material is made available to anyone wishing to use,
modify, copy, or redistribute it subject to the terms and conditions
@@ -10,83 +11,137 @@
*/
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
-//memcpy defined in memcpy-asm.S
+// memcpy defined in memcpy-asm.S
#else
-#include <string.h>
-#include <stdint.h>
#include "../../string/local.h"
+#include "xlenint.h"
+#include <string.h>
+#include <sys/asm.h>
#define unlikely(X) __builtin_expect (!!(X), 0)
-void *
-__inhibit_loop_to_libcall
-memcpy(void *__restrict aa, const void *__restrict bb, size_t n)
+static inline void
+__libc_memcpy_bytewise (unsigned char *dst, const unsigned char *src,
+ const size_t sz)
{
- #define BODY(a, b, t) { \
- t tt = *b; \
- a++, b++; \
- *(a - 1) = tt; \
- }
+ const unsigned char *end = dst + sz;
+ while (dst < end)
+ *dst++ = *src++;
+}
- char *a = (char *)aa;
- const char *b = (const char *)bb;
- char *end = a + n;
- uintptr_t msk = sizeof (long) - 1;
-#if __riscv_misaligned_slow || __riscv_misaligned_fast
- if (n < sizeof (long))
-#else
- if (unlikely ((((uintptr_t)a & msk) != ((uintptr_t)b & msk))
- || n < sizeof (long)))
+#ifndef __riscv_misaligned_fast
+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)
+{
+ unsigned char *a = (unsigned char *)aa;
+ const unsigned char *b = (const unsigned char *)bb;
+ unsigned char *end = a + n;
+ uintptr_t msk = SZREG - 1;
+ if (n < SZREG)
{
-small:
if (__builtin_expect (a < end, 1))
- while (a < end)
- BODY (a, b, char);
+ __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.
+ */
+#ifndef __riscv_misaligned_fast
+ 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))
- while ((uintptr_t)a & msk)
- BODY (a, b, char);
+ {
+ size_t pad = SZREG - ((uintptr_t)a & msk);
+ __libc_memcpy_bytewise (a, b, pad);
+ a += pad;
+ b += pad;
+ }
- long *la = (long *)a;
- const long *lb = (const long *)b;
- long *lend = (long *)((uintptr_t)end & ~msk);
+ uintxlen_t *la = (uintxlen_t *)a;
+ const uintxlen_t *lb = (const uintxlen_t *)b;
+ uintxlen_t *lend = (uintxlen_t *)((uintptr_t)end & ~msk);
if (unlikely (lend - la > 8))
{
while (lend - la > 8)
- {
- long b0 = *lb++;
- long b1 = *lb++;
- long b2 = *lb++;
- long b3 = *lb++;
- long b4 = *lb++;
- long b5 = *lb++;
- long b6 = *lb++;
- long b7 = *lb++;
- long b8 = *lb++;
- *la++ = b0;
- *la++ = b1;
- *la++ = b2;
- *la++ = b3;
- *la++ = b4;
- *la++ = b5;
- *la++ = b6;
- *la++ = b7;
- *la++ = b8;
- }
+ {
+ uintxlen_t b0 = *lb++;
+ uintxlen_t b1 = *lb++;
+ uintxlen_t b2 = *lb++;
+ uintxlen_t b3 = *lb++;
+ uintxlen_t b4 = *lb++;
+ uintxlen_t b5 = *lb++;
+ uintxlen_t b6 = *lb++;
+ uintxlen_t b7 = *lb++;
+ uintxlen_t b8 = *lb++;
+ *la++ = b0;
+ *la++ = b1;
+ *la++ = b2;
+ *la++ = b3;
+ *la++ = b4;
+ *la++ = b5;
+ *la++ = b6;
+ *la++ = b7;
+ *la++ = b8;
+ }
}
- while (la < lend)
- BODY (la, lb, long);
-
- a = (char *)la;
- b = (const char *)lb;
+ a = (unsigned char *)la;
+ b = (const unsigned char *)lb;
if (unlikely (a < end))
- goto small;
+ __libc_memcpy_bytewise (a, b, end - a);
return aa;
}
#endif
diff --git a/newlib/libc/machine/riscv/memmove.S b/newlib/libc/machine/riscv/memmove.S
index 66d9cd4..061472c 100644
--- a/newlib/libc/machine/riscv/memmove.S
+++ b/newlib/libc/machine/riscv/memmove.S
@@ -14,26 +14,26 @@
.global memmove
.type memmove, @function
memmove:
- beqz a2, 2f
+ beqz a2, .Ldone /* in case there are 0 bytes to be copied, return immediately */
- mv t1, a0
+ mv a4, a0 /* copy the destination address over to a4, since memmove should return that address in a0 at the end */
li a3, 1
- bgtu a1, a0, 1f
+ bgtu a1, a0, .Lcopy /* in case of source address > destination address, copy from start to end of the specified memory area */
- li a3, -1
- addi a4, a2 , -1
- add t1, t1, a4
- add a1, a1, a4
+ li a3, -1 /* otherwhise, start copying from the end of the specified memory area in order to prevent data loss in case of overlapping memory areas.*/
+ add a4, a4, a2 /* add the number of bytes to be copied to both addresses. this gives us the address one byte past the end of the memory area we want to copy, */
+ add a1, a1, a2 /* therefore we need to subtract 1 from both addresses in the next step before starting the copying process. */
-1:
- lb t2, 0(a1)
- sb t2, 0(t1)
- add a2, a2, -1
- add t1, t1, a3
+.Lincrement:
+ add a4, a4, a3 /* in case of source address < destination address, increment both addresses by -1 before copying any data to obtain the correct start addresses */
add a1, a1, a3
- bnez a2, 1b
+.Lcopy:
+ lbu a5, 0(a1)
+ addi a2, a2, -1 /* copy bytes as long as a2 (= the number of bytes to be copied) > 0. the increment is done here to relax the RAW dependency between load and store */
+ sb a5, 0(a4)
+ bnez a2, .Lincrement
-2:
+.Ldone:
ret
.size memmove, .-memmove
diff --git a/newlib/libc/machine/riscv/memrchr.c b/newlib/libc/machine/riscv/memrchr.c
new file mode 100644
index 0000000..47e1023
--- /dev/null
+++ b/newlib/libc/machine/riscv/memrchr.c
@@ -0,0 +1,172 @@
+/*
+FUNCTION
+ <<memrchr>>---reverse search for character in memory
+
+INDEX
+ memrchr
+
+SYNOPSIS
+ #include <string.h>
+ void *memrchr(const void *<[src]>, int <[c]>, size_t <[length]>);
+
+DESCRIPTION
+ This function searches memory starting at <[length]> bytes
+ beyond <<*<[src]>>> backwards for the character <[c]>.
+ The search only ends with the first occurrence of <[c]>; in
+ particular, <<NUL>> does not terminate the search.
+
+RETURNS
+ If the character <[c]> is found within <[length]> characters
+ of <<*<[src]>>>, a pointer to the character is returned. If
+ <[c]> is not found, then <<NULL>> is returned.
+
+PORTABILITY
+<<memrchr>> is a GNU extension.
+
+<<memrchr>> requires no supporting OS subroutines.
+
+QUICKREF
+ memrchr
+*/
+
+#include <sys/asm.h>
+#include <stddef.h>
+#include "rv_string.h"
+
+// Move size
+#if __riscv_zilsd
+#define MV_SZ 8
+
+// Offset is only 4 bytes for Zilsd/Zclsd since each register is 32 bits
+#define OFFSET 4
+#else
+#define MV_SZ SZREG
+#define OFFSET SZREG
+#endif
+
+
+void *
+memrchr (const void *src_void,
+ int c,
+ size_t length)
+{
+ const unsigned char *src = (const unsigned char *) src_void;
+ unsigned char d = c;
+
+ if (length) src += length - 1;
+
+#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
+
+ /*
+ We add one to the address because even if an address is already aligned,
+ when loading words the bytes preceding this address are read, so check
+ the single byte.
+
+ If the address has all the least significant bits set equaling MV_SZ - 1,
+ and has a length of at least MV_SZ, we can read a word starting from
+ src & ~(MV_SZ - 1) because no alignment is actually required
+ */
+ size_t align = (uintptr_t) (src + 1) & (MV_SZ - 1);
+
+ if (align)
+ {
+ if (length < align) align = length;
+
+ switch (align)
+ {
+#if MV_SZ == 8
+ case 7:
+ if (*src-- == d) return (void *) (src + 1);
+ case 6:
+ if (*src-- == d) return (void *) (src + 1);
+ case 5:
+ if (*src-- == d) return (void *) (src + 1);
+ case 4:
+ if (*src-- == d) return (void *) (src + 1);
+#endif /* MV_SZ == 8 */
+ case 3:
+ if (*src-- == d) return (void *) (src + 1);
+ case 2:
+ if (*src-- == d) return (void *) (src + 1);
+ case 1:
+ if (*src-- == d) return (void *) (src + 1);
+ }
+
+ length -= align;
+ }
+
+ const unsigned char *end_addr = src - (length & ~(MV_SZ - 1));
+
+ if (src > end_addr)
+ {
+ src -= MV_SZ - 1;
+
+ uintxlen_t mask = __libc_splat_byte(d);
+
+ do
+ {
+ uintlslen_t val = *(uintlslen_t*) src;
+
+#if __riscv_zilsd
+ uintxlen_t word2 = val >> 32;
+ word2 ^= mask;
+
+ if (__libc_detect_null(word2))
+ {
+#if __riscv_zbb
+ src += OFFSET;
+ word2 = ~__LIBC_RISCV_ZBB_ORC_B(word2);
+ word2 = __LIBC_RISCV_ZBB_CNT_Z_REV(word2);
+
+ return (void *) (src + OFFSET - 1 - (word2 >> 3));
+#else /* not __riscv_zbb */
+ src += MV_SZ - 1;
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+ return (void *) src;
+#endif /* __riscv_zbb */
+ }
+#endif /* __riscv_zilsd */
+ uintxlen_t word1 = val ^ mask;
+
+ if (__libc_detect_null(word1))
+ {
+#if __riscv_zbb
+ word1 = ~__LIBC_RISCV_ZBB_ORC_B(word1);
+ word1 = __LIBC_RISCV_ZBB_CNT_Z_REV(word1);
+
+ return (void *) (src + OFFSET - 1 - (word1 >> 3));
+#else /* not __riscv_zbb */
+ src += OFFSET - 1;
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+#if __riscv_xlen == 64
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+ if (*src-- == d) return (void *) (src + 1);
+#endif /* __riscv_xlen == 64 */
+ return (void *) src;
+#endif /* __riscv_zbb */
+ }
+
+ src -= MV_SZ;
+ } while (src > end_addr);
+
+ length &= MV_SZ - 1;
+ src = end_addr;
+ }
+
+#endif /* not PREFER_SIZE_OVER_SPEED */
+
+ while (length--)
+ {
+ if (*src == d)
+ return (void *) src;
+ src--;
+ }
+
+ return NULL;
+}
diff --git a/newlib/libc/machine/riscv/memset.S b/newlib/libc/machine/riscv/memset.S
index a717ae7..533f667 100644
--- a/newlib/libc/machine/riscv/memset.S
+++ b/newlib/libc/machine/riscv/memset.S
@@ -9,105 +9,296 @@
http://www.opensource.org/licenses.
*/
+#include <sys/asm.h>
+
+
+#define BYTE_TBL_SZ 31
+#define WORD_TBL_SZ 32
+
+#if __riscv_zilsd
+/* Move size */
+#define MV_SZ 8
+
+/* Store instruction */
+#define RG_ST sd
+
+/* Zilsd and Zclsd require an even numbered register */
+#define REG_SPLAT a4
+#else
+#define MV_SZ SZREG
+#define RG_ST REG_S
+#define REG_SPLAT a1
+#endif
+
+/*
+ Use an extended register for Zilsd and Zclsd if available
+ since a5 is used for the odd numbered register, in order
+ to eliminate an li instruction
+*/
+#if __riscv_zilsd && !__riscv_abi_rve
+#define REG_TABLE a6
+#else
+#define REG_TABLE a5
+#endif
+
+
.text
.global memset
-.type memset, @function
+.type memset, @function
+
+/* void *memset(void *s, int c, size_t n); */
+
+
memset:
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
- mv t1, a0
- beqz a2, 2f
+ mv a3, a0
+ beqz a2, .Ldone
-1:
- sb a1, 0(t1)
- add a2, a2, -1
- add t1, t1, 1
- bnez a2, 1b
+.Lset:
+ sb a1, 0(a3)
+ addi a2, a2, -1
+ addi a3, a3, 1
+ bnez a2, .Lset
-2:
+.Ldone:
ret
#else
- li t1, 15
- move a4, a0
- bleu a2, t1, .Ltiny
- and a5, a4, 15
- bnez a5, .Lmisaligned
+ li REG_TABLE, BYTE_TBL_SZ
+ mv a3, a0
+
+ /* If there aren't many bytes, copy them individually to reduce overhead */
+ bleu a2, REG_TABLE, .Lcopy_bytes
+
+ and a4, a3, MV_SZ - 1
+ beqz a4, .Lword_check
+
+ /*
+ Jump into the byte table depending on the number of bytes that need to be
+ written
+ */
+1:
+ auipc t0, %pcrel_hi(.Ltable_misaligned)
+
+ /*
+ Instructions in the tables are forced to be four bytes, so scale count
+ by 4
+ */
+#if __riscv_zba
+ sh2add t0, a4, t0
+#else
+ sll t1, a4, 2
+ add t0, t0, t1
+#endif
-.Laligned:
- bnez a1, .Lwordify
+ /* Save the return address because we aren't exiting the function yet */
+ mv t1, ra
+ jalr t0, %pcrel_lo(1b)
-.Lwordified:
- and a3, a2, ~15
- and a2, a2, 15
- add a3, a3, a4
+ /* Update pointer and count by what was written */
+ mv ra, t1
+ add a4, a4, -MV_SZ
+ add a2, a2, a4
+ sub a3, a3, a4
+ /* Access is now aligned. Check we can copy words. */
+ bleu a2, REG_TABLE, .Lcopy_bytes
+
+.Lword_check:
+ /* Don't need to splat special case of zero */
+ bnez a1, .Lsplat_byte
+#if __riscv_zilsd
+ mv REG_SPLAT, a1
+#endif
+ j .Lcopy_words_init
+
+/*
+ Align labels to four bytes after unconditional jumps to avoid any
+ penalties when jumping to 32-bit instructions that aren't 4-byte
+ aligned
+*/
+.p2align 2
+.Lsplat_byte:
+#if __riscv_zbkb
+ packh REG_SPLAT, a1, a1
#if __riscv_xlen == 64
-1:sd a1, 0(a4)
- sd a1, 8(a4)
+ packw REG_SPLAT, REG_SPLAT, REG_SPLAT
+#endif
+ pack REG_SPLAT, REG_SPLAT, REG_SPLAT
#else
-1:sw a1, 0(a4)
- sw a1, 4(a4)
- sw a1, 8(a4)
- sw a1, 12(a4)
+ and a1, a1, 0xFF
+ sll t0, a1, 8
+ or a1, a1, t0
+ sll t0, a1, 16
+ or REG_SPLAT, a1, t0
+#if __riscv_xlen == 64
+ sll t0, REG_SPLAT, 32
+ or REG_SPLAT, REG_SPLAT, t0
+#endif
#endif
- add a4, a4, 16
- bltu a4, a3, 1b
- bnez a2, .Ltiny
- ret
+.Lcopy_words_init:
+#if __riscv_zilsd
+ /* Odd register of even-odd pair */
+ mv a5, REG_SPLAT
+#endif
+
+ /* Calculate end address */
+ and t0, a2, ~(MV_SZ - 1)
+ add t1, a3, t0
+
+ /*
+ The idea behind the table of word copies is that first we calculate any
+ remainder of bytes that need to be copied by the table that aren't an
+ entire table length. That's copied first. After that, runs of the entire
+ table are performed.
+ */
+ and t0, t0, (WORD_TBL_SZ - 1) * MV_SZ
+
+ /* Skip if there's no remainder */
+ beqz t0, .Ltable_bigly
+ neg t0, t0
+ add t0, t0, WORD_TBL_SZ * MV_SZ
+
+ /* Adjust start address with offset */
+ sub a3, a3, t0
+
+1:
+ auipc t2, %pcrel_hi(.Ltable_bigly)
+
+#if MV_SZ == 8
+ /*
+ If eight bytes are being copied with each store, we need to divide
+ the table offset in half
+ */
+ srl t0, t0, 1
+#endif
+
+ add t2, t2, t0
+ jr t2, %pcrel_lo(1b)
-.Ltiny:
- sub a3, t1, a2
- sll a3, a3, 2
-1:auipc t0, %pcrel_hi(.Ltable)
- add a3, a3, t0
+.p2align 2
+.Ltable_bigly:
+/*
+ Force the instructions to be four bytes to avoid an extra instruction
+ that would be needed to halve the offset for sw
+*/
.option push
.option norvc
-.Ltable_misaligned:
- jr a3, %pcrel_lo(1b)
-.Ltable:
- sb a1,14(a4)
- sb a1,13(a4)
- sb a1,12(a4)
- sb a1,11(a4)
- sb a1,10(a4)
- sb a1, 9(a4)
- sb a1, 8(a4)
- sb a1, 7(a4)
- sb a1, 6(a4)
- sb a1, 5(a4)
- sb a1, 4(a4)
- sb a1, 3(a4)
- sb a1, 2(a4)
- sb a1, 1(a4)
- sb a1, 0(a4)
+ RG_ST REG_SPLAT, MV_SZ*0(a3)
+ RG_ST REG_SPLAT, MV_SZ*1(a3)
+ RG_ST REG_SPLAT, MV_SZ*2(a3)
+ RG_ST REG_SPLAT, MV_SZ*3(a3)
+ RG_ST REG_SPLAT, MV_SZ*4(a3)
+ RG_ST REG_SPLAT, MV_SZ*5(a3)
+ RG_ST REG_SPLAT, MV_SZ*6(a3)
+ RG_ST REG_SPLAT, MV_SZ*7(a3)
+ RG_ST REG_SPLAT, MV_SZ*8(a3)
+ RG_ST REG_SPLAT, MV_SZ*9(a3)
+ RG_ST REG_SPLAT, MV_SZ*10(a3)
+ RG_ST REG_SPLAT, MV_SZ*11(a3)
+ RG_ST REG_SPLAT, MV_SZ*12(a3)
+ RG_ST REG_SPLAT, MV_SZ*13(a3)
+ RG_ST REG_SPLAT, MV_SZ*14(a3)
+ RG_ST REG_SPLAT, MV_SZ*15(a3)
+ RG_ST REG_SPLAT, MV_SZ*16(a3)
+ RG_ST REG_SPLAT, MV_SZ*17(a3)
+ RG_ST REG_SPLAT, MV_SZ*18(a3)
+ RG_ST REG_SPLAT, MV_SZ*19(a3)
+ RG_ST REG_SPLAT, MV_SZ*20(a3)
+ RG_ST REG_SPLAT, MV_SZ*21(a3)
+ RG_ST REG_SPLAT, MV_SZ*22(a3)
+ RG_ST REG_SPLAT, MV_SZ*23(a3)
+ RG_ST REG_SPLAT, MV_SZ*24(a3)
+ RG_ST REG_SPLAT, MV_SZ*25(a3)
+ RG_ST REG_SPLAT, MV_SZ*26(a3)
+ RG_ST REG_SPLAT, MV_SZ*27(a3)
+ RG_ST REG_SPLAT, MV_SZ*28(a3)
+ RG_ST REG_SPLAT, MV_SZ*29(a3)
+ RG_ST REG_SPLAT, MV_SZ*30(a3)
+ RG_ST REG_SPLAT, MV_SZ*31(a3)
.option pop
- ret
-.Lwordify:
- and a1, a1, 0xFF
- sll a3, a1, 8
- or a1, a1, a3
- sll a3, a1, 16
- or a1, a1, a3
-#if __riscv_xlen == 64
- sll a3, a1, 32
- or a1, a1, a3
+ /* Update the pointer and copy data if needed */
+ add a3, a3, MV_SZ * WORD_TBL_SZ
+ bltu a3, t1, .Ltable_bigly
+
+ /* Copy any remaining bytes */
+ and a2, a2, MV_SZ - 1
+ beqz a2, .Lexit
+
+#if __riscv_zilsd && __riscv_abi_rve
+ /* Restore table size if necessary */
+ li REG_TABLE, BYTE_TBL_SZ
#endif
- j .Lwordified
-
-.Lmisaligned:
- sll a3, a5, 2
-1:auipc t0, %pcrel_hi(.Ltable_misaligned)
- add a3, a3, t0
- mv t0, ra
- jalr a3, %pcrel_lo(1b)
- mv ra, t0
-
- add a5, a5, -16
- sub a4, a4, a5
- add a2, a2, a5
- bleu a2, t1, .Ltiny
- j .Laligned
+
+.Lcopy_bytes:
+ auipc t0, %pcrel_hi(.Ltable_tiny)
+
+ sub a2, REG_TABLE, a2
+
+ /*
+ Instructions in the tables are forced to be four bytes, so scale count
+ by 4
+ */
+#if __riscv_zba
+ sh2add t0, a2, t0
+#else
+ sll a2, a2, 2
+ add t0, t0, a2
+#endif
+
+ /* Don't save the return address because we're exiting after the jump */
+ jr t0, %pcrel_lo(.Lcopy_bytes)
+
+.p2align 2
+.Ltable_tiny:
+/*
+ norvc is needed because the immediate is only two bits in size for c.sb,
+ and without it the table would have a mix of 2- and 4-byte instructions
+ when Zcb is available
+*/
+.option push
+.option norvc
+ sb a1, 30(a3)
+ sb a1, 29(a3)
+ sb a1, 28(a3)
+ sb a1, 27(a3)
+ sb a1, 26(a3)
+ sb a1, 25(a3)
+ sb a1, 24(a3)
+ sb a1, 23(a3)
+ sb a1, 22(a3)
+ sb a1, 21(a3)
+ sb a1, 20(a3)
+ sb a1, 19(a3)
+ sb a1, 18(a3)
+ sb a1, 17(a3)
+ sb a1, 16(a3)
+ sb a1, 15(a3)
+ sb a1, 14(a3)
+ sb a1, 13(a3)
+ sb a1, 12(a3)
+ sb a1, 11(a3)
+ sb a1, 10(a3)
+ sb a1, 9(a3)
+ sb a1, 8(a3)
+#if MV_SZ == 8
+.Ltable_misaligned:
+#endif
+ sb a1, 7(a3)
+ sb a1, 6(a3)
+ sb a1, 5(a3)
+ sb a1, 4(a3)
+#if MV_SZ == 4
+.Ltable_misaligned:
+#endif
+ sb a1, 3(a3)
+ sb a1, 2(a3)
+ sb a1, 1(a3)
+ sb a1, 0(a3)
+.option pop
+.Lexit:
+ ret
#endif
- .size memset, .-memset
+.size memset, .-memset
diff --git a/newlib/libc/machine/riscv/rv_string.h b/newlib/libc/machine/riscv/rv_string.h
index 362f66a..dc2a26d 100644
--- a/newlib/libc/machine/riscv/rv_string.h
+++ b/newlib/libc/machine/riscv/rv_string.h
@@ -20,20 +20,24 @@
// Determine which intrinsics to use based on XLEN and endianness
#if __riscv_xlen == 64
- #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_64(x)
+ #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_64(x)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_64(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_64(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z_REV(x) __riscv_clz_64(x)
#else
- #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_64(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_64(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z_REV(x) __riscv_ctz_64(x)
#endif
#else
- #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_32(x)
+ #define __LIBC_RISCV_ZBB_ORC_B(x) __riscv_orc_b_32(x)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_32(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_ctz_32(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z_REV(x) __riscv_clz_32(x)
#else
- #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_32(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z(x) __riscv_clz_32(x)
+ #define __LIBC_RISCV_ZBB_CNT_Z_REV(x) __riscv_ctz_32(x)
#endif
#endif
#endif
@@ -82,8 +86,8 @@ static __inline char *__libc_strcpy(char *dst, const char *src, bool ret_start)
if (!(*dst++ = src[0])) return dst0;
if (!(*dst++ = src[1])) return dst0;
if (!(*dst++ = src[2])) return dst0;
- if (!(*dst++ = src[3])) return dst0;
#if __riscv_xlen == 64
+ if (!(*dst++ = src[3])) return dst0;
if (!(*dst++ = src[4])) return dst0;
if (!(*dst++ = src[5])) return dst0;
if (!(*dst++ = src[6])) return dst0;
@@ -94,13 +98,13 @@ static __inline char *__libc_strcpy(char *dst, const char *src, bool ret_start)
if (!(*dst++ = src[0])) return dst - 1;
if (!(*dst++ = src[1])) return dst - 1;
if (!(*dst++ = src[2])) return dst - 1;
- if (!(*dst++ = src[3])) return dst - 1;
#if __riscv_xlen == 64
+ if (!(*dst++ = src[3])) return dst - 1;
if (!(*dst++ = src[4])) return dst - 1;
if (!(*dst++ = src[5])) return dst - 1;
if (!(*dst++ = src[6])) return dst - 1;
- dst0 = dst;
#endif
+ dst0 = dst;
}
*dst = 0;
@@ -121,4 +125,33 @@ static __inline char *__libc_strcpy(char *dst, const char *src, bool ret_start)
}
+static __inline uintxlen_t __libc_splat_byte(unsigned char c)
+{
+ uintxlen_t val;
+
+#if __riscv_zbkb
+ asm volatile ("packh %0, %1, %1"
+ : "=r" (val)
+ : "r" (c)
+ );
+#if __riscv_xlen == 64
+ asm volatile ("packw %0, %0, %0"
+ : "+r" (val)
+ );
+#endif /* __riscv_xlen == 64 */
+ asm volatile ("pack %0, %0, %0"
+ : "+r" (val)
+ );
+#else /* not __riscv_zbkb */
+ val = (c << 8) | c;
+ val = (val << 16) | val;
+#if __riscv_xlen == 64
+ val = (val << 32) | val;
+#endif /* __riscv_xlen == 64 */
+#endif /* __riscv_zbkb */
+
+ return val;
+}
+
+
#endif /* _RV_STRING_H */
diff --git a/newlib/libc/machine/riscv/setjmp.S b/newlib/libc/machine/riscv/setjmp.S
index eef242e..f2b5053 100644
--- a/newlib/libc/machine/riscv/setjmp.S
+++ b/newlib/libc/machine/riscv/setjmp.S
@@ -16,21 +16,33 @@
.type setjmp, @function
setjmp:
REG_S ra, 0*SZREG(a0)
- REG_S s0, 1*SZREG(a0)
- REG_S s1, 2*SZREG(a0)
+ #if __riscv_xlen == 32 && (__riscv_zilsd) && (__riscv_misaligned_fast)
+ sd s0, 1*SZREG(a0)
+ #else
+ REG_S s0, 1*SZREG(a0)
+ REG_S s1, 2*SZREG(a0)
+ #endif
-#ifndef __riscv_32e
- REG_S s2, 3*SZREG(a0)
- REG_S s3, 4*SZREG(a0)
- REG_S s4, 5*SZREG(a0)
- REG_S s5, 6*SZREG(a0)
- REG_S s6, 7*SZREG(a0)
- REG_S s7, 8*SZREG(a0)
- REG_S s8, 9*SZREG(a0)
- REG_S s9, 10*SZREG(a0)
- REG_S s10,11*SZREG(a0)
- REG_S s11,12*SZREG(a0)
- REG_S sp, 13*SZREG(a0)
+#ifndef __riscv_abi_rve
+ #if __riscv_xlen == 32 && (__riscv_zilsd) && (__riscv_misaligned_fast)
+ sd s2, 3*SZREG(a0)
+ sd s4, 5*SZREG(a0)
+ sd s6, 7*SZREG(a0)
+ sd s8, 9*SZREG(a0)
+ sd s10,11*SZREG(a0)
+ #else
+ REG_S s2, 3*SZREG(a0)
+ REG_S s3, 4*SZREG(a0)
+ REG_S s4, 5*SZREG(a0)
+ REG_S s5, 6*SZREG(a0)
+ REG_S s6, 7*SZREG(a0)
+ REG_S s7, 8*SZREG(a0)
+ REG_S s8, 9*SZREG(a0)
+ REG_S s9, 10*SZREG(a0)
+ REG_S s10,11*SZREG(a0)
+ REG_S s11,12*SZREG(a0)
+ #endif
+ REG_S sp, 13*SZREG(a0)
#else
REG_S sp, 3*SZREG(a0)
#endif
@@ -59,19 +71,31 @@ setjmp:
.type longjmp, @function
longjmp:
REG_L ra, 0*SZREG(a0)
- REG_L s0, 1*SZREG(a0)
- REG_L s1, 2*SZREG(a0)
-#ifndef __riscv_32e
- REG_L s2, 3*SZREG(a0)
- REG_L s3, 4*SZREG(a0)
- REG_L s4, 5*SZREG(a0)
- REG_L s5, 6*SZREG(a0)
- REG_L s6, 7*SZREG(a0)
- REG_L s7, 8*SZREG(a0)
- REG_L s8, 9*SZREG(a0)
- REG_L s9, 10*SZREG(a0)
- REG_L s10,11*SZREG(a0)
- REG_L s11,12*SZREG(a0)
+ #if __riscv_xlen == 32 && (__riscv_zilsd) && (__riscv_misaligned_fast)
+ ld s0, 1*SZREG(a0)
+ #else
+ REG_L s0, 1*SZREG(a0)
+ REG_L s1, 2*SZREG(a0)
+ #endif
+#ifndef __riscv_abi_rve
+ #if __riscv_xlen == 32 && (__riscv_zilsd) && (__riscv_misaligned_fast)
+ ld s2, 3*SZREG(a0)
+ ld s4, 5*SZREG(a0)
+ ld s6, 7*SZREG(a0)
+ ld s8, 9*SZREG(a0)
+ ld s10,11*SZREG(a0)
+ #else
+ REG_L s2, 3*SZREG(a0)
+ REG_L s3, 4*SZREG(a0)
+ REG_L s4, 5*SZREG(a0)
+ REG_L s5, 6*SZREG(a0)
+ REG_L s6, 7*SZREG(a0)
+ REG_L s7, 8*SZREG(a0)
+ REG_L s8, 9*SZREG(a0)
+ REG_L s9, 10*SZREG(a0)
+ REG_L s10,11*SZREG(a0)
+ REG_L s11,12*SZREG(a0)
+ #endif
REG_L sp, 13*SZREG(a0)
#else
REG_L sp, 3*SZREG(a0)
diff --git a/newlib/libc/machine/riscv/strcmp.S b/newlib/libc/machine/riscv/strcmp.S
index cc29b7b..0b1dfc4 100644
--- a/newlib/libc/machine/riscv/strcmp.S
+++ b/newlib/libc/machine/riscv/strcmp.S
@@ -16,15 +16,15 @@
.type strcmp, @function
strcmp:
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
-1:
+.Lcompare:
lbu a2, 0(a0)
lbu a3, 0(a1)
- add a0, a0, 1
- add a1, a1, 1
- bne a2, a3, 2f
- bnez a2, 1b
+ addi a0, a0, 1
+ addi a1, a1, 1
+ bne a2, a3, .Lreturn_diff
+ bnez a2, .Lcompare
-2:
+.Lreturn_diff:
sub a0, a2, a3
ret
@@ -48,12 +48,16 @@ strcmp:
REG_L a2, \i*SZREG(a0)
REG_L a3, \i*SZREG(a1)
- and t0, a2, a5
- or t1, a2, a5
- add t0, t0, a5
- or t0, t0, t1
+ #if __riscv_zbb
+ orc.b a4, a2
+ #else
+ and a4, a2, a5
+ or t1, a2, a5
+ add a4, a4, a5
+ or a4, a4, t1
+ #endif
- bne t0, t2, .Lnull\i
+ bne a4, t2, .Lnull\i
.if \i+1-\n
bne a2, a3, .Lmismatch
.else
@@ -95,73 +99,109 @@ strcmp:
.Lmismatch:
# words don't match, but a2 has no null byte.
+ #if __riscv_zbb
+ xor a4, a2, a3 # find differing bits
+
+ # Check system endianness
+ # If little-endian, use Count Trailing Zeros (ctz)
+ # If big-endian, use Count Leading Zeros (clz)
+ # This helps identify the position of the first differing byte between a2 and a3.
+
+ # For example, in little-endian, least significant byte comes first.
+ # So trailing zeros help find which byte position differs.
+
+ # In big-endian, most significant byte comes first, so leading zeros are used.
+ # The position will then be used to extract the differing byte.
+
+ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ ctz a5, a4
+ #else
+ clz a5, a4
+ #endif
+
+ andi a5, a5, -8 # find position of bit offset to the start of the byte where the first difference occurs
+
+
+ # Shift a2 and a3 right by a5 bits to bring the target byte to the LSB, and isolate the byte of interest
+ srl a2, a2, a5
+ and a2, a2, 0xff
+
+ srl a3, a3, a5
+ and a3, a3, 0xff
+
+
+ sub a0, a2, a3 # Calculate and return the difference in the isolated bytes
+ ret
+
+ #else
+ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ #if __riscv_xlen == 64
+ sll a4, a2, 48
+ sll a5, a3, 48
+ bne a4, a5, .Lmismatch_upper
+ sll a4, a2, 32
+ sll a5, a3, 32
+ bne a4, a5, .Lmismatch_upper
+ #endif
+ sll a4, a2, 16
+ sll a5, a3, 16
+ bne a4, a5, .Lmismatch_upper
+
+ srl a4, a2, 8*SZREG-16
+ srl a5, a3, 8*SZREG-16
+ sub a0, a4, a5
+ and a1, a0, 0xff
+ bnez a1, .Lfinal_upper_diff
+ ret
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-
-#if __riscv_xlen == 64
- sll a4, a2, 48
- sll a5, a3, 48
- bne a4, a5, .Lmismatch_upper
- sll a4, a2, 32
- sll a5, a3, 32
- bne a4, a5, .Lmismatch_upper
-#endif
- sll a4, a2, 16
- sll a5, a3, 16
- bne a4, a5, .Lmismatch_upper
-
- srl a4, a2, 8*SZREG-16
- srl a5, a3, 8*SZREG-16
- sub a0, a4, a5
- and a1, a0, 0xff
- bnez a1, 1f
- ret
-
-.Lmismatch_upper:
- srl a4, a4, 8*SZREG-16
- srl a5, a5, 8*SZREG-16
- sub a0, a4, a5
- and a1, a0, 0xff
- bnez a1, 1f
- ret
-
-1:and a4, a4, 0xff
- and a5, a5, 0xff
- sub a0, a4, a5
- ret
-
-#else
-
-#if __riscv_xlen == 64
- srl a4, a2, 48
- srl a5, a3, 48
- bne a4, a5, .Lmismatch_lower
- srl a4, a2, 32
- srl a5, a3, 32
- bne a4, a5, .Lmismatch_lower
-#endif
- srl a4, a2, 16
- srl a5, a3, 16
- bne a4, a5, .Lmismatch_lower
-
- srl a4, a2, 8
- srl a5, a3, 8
- bne a4, a5, 1f
- and a4, a2, 0xff
- and a5, a3, 0xff
-1:sub a0, a4, a5
- ret
-
-.Lmismatch_lower:
- srl a2, a4, 8
- srl a3, a5, 8
- bne a2, a3, 1f
- and a2, a4, 0xff
- and a3, a5, 0xff
-1:sub a0, a2, a3
- ret
-
-#endif
+ .Lmismatch_upper:
+ srl a4, a4, 8*SZREG-16
+ srl a5, a5, 8*SZREG-16
+ sub a0, a4, a5
+ and a1, a0, 0xff
+ bnez a1, .Lfinal_upper_diff
+ ret
+
+ .Lfinal_upper_diff:
+ and a4, a4, 0xff
+ and a5, a5, 0xff
+ sub a0, a4, a5
+ ret
+ #else
+ #if __riscv_xlen == 64
+ srl a4, a2, 48
+ srl a5, a3, 48
+ bne a4, a5, .Lmismatch_lower
+ srl a4, a2, 32
+ srl a5, a3, 32
+ bne a4, a5, .Lmismatch_lower
+ #endif
+ srl a4, a2, 16
+ srl a5, a3, 16
+ bne a4, a5, .Lmismatch_lower
+
+ srl a4, a2, 8
+ srl a5, a3, 8
+ bne a4, a5, .Lbyte_diff
+ and a4, a2, 0xff
+ and a5, a3, 0xff
+
+ .Lbyte_diff:
+ sub a0, a4, a5
+ ret
+
+ .Lmismatch_lower:
+ srl a2, a4, 8
+ srl a3, a5, 8
+ bne a2, a3, .Lfinal_lower_diff
+ and a2, a4, 0xff
+ and a3, a5, 0xff
+
+ .Lfinal_lower_diff:
+ sub a0, a2, a3
+ ret
+ #endif
+ #endif
.Lmisaligned:
# misaligned
@@ -169,10 +209,10 @@ strcmp:
lbu a3, 0(a1)
add a0, a0, 1
add a1, a1, 1
- bne a2, a3, 1f
+ bne a2, a3, .Lmisaligned_diff
bnez a2, .Lmisaligned
-1:
+.Lmisaligned_diff:
sub a0, a2, a3
ret
diff --git a/newlib/libc/machine/riscv/strlen.c b/newlib/libc/machine/riscv/strlen.c
index 9bfd2a1..8ab5ce5 100644
--- a/newlib/libc/machine/riscv/strlen.c
+++ b/newlib/libc/machine/riscv/strlen.c
@@ -9,6 +9,7 @@
http://www.opensource.org/licenses.
*/
+#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include "rv_string.h"
@@ -38,7 +39,9 @@ size_t strlen(const char *str)
asm volatile ("" : "+r"(ps)); /* prevent "optimization" */
str = (const char *)ps;
- size_t ret = str - start, sp = sizeof (*ps);
+
+ size_t ret = str - start;
+ ssize_t sp = sizeof (*ps);
#if __riscv_zbb
psval = ~__LIBC_RISCV_ZBB_ORC_B(psval);
@@ -47,16 +50,16 @@ size_t strlen(const char *str)
return ret + (psval >> 3) - sp;
#else
char c0 = str[0 - sp], c1 = str[1 - sp], c2 = str[2 - sp], c3 = str[3 - sp];
- if (c0 == 0) return ret + 0 - sp;
- if (c1 == 0) return ret + 1 - sp;
- if (c2 == 0) return ret + 2 - sp;
- if (c3 == 0) return ret + 3 - sp;
+ if (c0 == 0) return ret + 0 - sp;
+ if (c1 == 0) return ret + 1 - sp;
+ if (c2 == 0) return ret + 2 - sp;
+ if (__riscv_xlen == 32 || c3 == 0) return ret + 3 - sp;
#if __riscv_xlen == 64
c0 = str[4 - sp], c1 = str[5 - sp], c2 = str[6 - sp];
- if (c0 == 0) return ret + 4 - sp;
- if (c1 == 0) return ret + 5 - sp;
- if (c2 == 0) return ret + 6 - sp;
+ if (c0 == 0) return ret + 4 - sp;
+ if (c1 == 0) return ret + 5 - sp;
+ if (c2 == 0) return ret + 6 - sp;
#endif
return ret + 7 - sp;
diff --git a/newlib/libc/machine/riscv/xlenint.h b/newlib/libc/machine/riscv/xlenint.h
index 86363a8..2d444ff 100644
--- a/newlib/libc/machine/riscv/xlenint.h
+++ b/newlib/libc/machine/riscv/xlenint.h
@@ -11,4 +11,11 @@ typedef uint32_t uintxlen_t;
# error __riscv_xlen must equal 32 or 64
#endif
+/* Load/Store length */
+#if __riscv_zilsd
+typedef uint64_t uintlslen_t;
+#else
+typedef uintxlen_t uintlslen_t;
+#endif
+
#endif /* _XLENINT_H */
diff --git a/newlib/libc/posix/ftw.c b/newlib/libc/posix/ftw.c
index 79e6358..e3ca85c 100644
--- a/newlib/libc/posix/ftw.c
+++ b/newlib/libc/posix/ftw.c
@@ -30,7 +30,9 @@ int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int
/* The following cast assumes that calling a function with one
* argument more than it needs behaves as expected. This is
* actually undefined, but works on all real-world machines. */
- return nftw(path, (int (*)())fn, fd_limit, FTW_PHYS);
+ return nftw(path,
+ (int (*)(const char *, const struct stat *, int, struct FTW *))fn,
+ fd_limit, FTW_PHYS);
}
#endif /* ! HAVE_OPENDIR */
diff --git a/newlib/libc/posix/glob.c b/newlib/libc/posix/glob.c
index 20eec02..fe7359b 100644
--- a/newlib/libc/posix/glob.c
+++ b/newlib/libc/posix/glob.c
@@ -157,10 +157,8 @@ static void qprintf(const char *, Char *);
#endif
int
-glob(pattern, flags, errfunc, pglob)
- const char *__restrict pattern;
- int flags, (*errfunc)(const char *, int);
- glob_t *__restrict pglob;
+glob(const char *__restrict pattern, int flags,
+ int (*errfunc)(const char *, int), glob_t *__restrict pglob)
{
const u_char *patnext;
int c, limit;
@@ -215,10 +213,7 @@ glob(pattern, flags, errfunc, pglob)
* characters
*/
static int
-globexp1(pattern, pglob, limit)
- const Char *pattern;
- glob_t *pglob;
- int *limit;
+globexp1(const Char *pattern, glob_t *pglob, int *limit)
{
const Char* ptr = pattern;
int rv;
@@ -241,10 +236,8 @@ globexp1(pattern, pglob, limit)
* If it fails then it tries to glob the rest of the pattern and returns.
*/
static int
-globexp2(ptr, pattern, pglob, rv, limit)
- const Char *ptr, *pattern;
- glob_t *pglob;
- int *rv, *limit;
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
+ int *limit)
{
int i;
Char *lm, *ls;
@@ -348,11 +341,7 @@ globexp2(ptr, pattern, pglob, rv, limit)
* expand tilde from the passwd file.
*/
static const Char *
-globtilde(pattern, patbuf, patbuf_len, pglob)
- const Char *pattern;
- Char *patbuf;
- size_t patbuf_len;
- glob_t *pglob;
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
{
struct passwd *pwd;
char *h;
@@ -428,10 +417,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
* to find no matches.
*/
static int
-glob0(pattern, pglob, limit)
- const Char *pattern;
- glob_t *pglob;
- int *limit;
+glob0(const Char *pattern, glob_t *pglob, int *limit)
{
const Char *qpatnext;
int c, err, oldpathc;
@@ -517,17 +503,13 @@ glob0(pattern, pglob, limit)
}
static int
-compare(p, q)
- const void *p, *q;
+compare(const void *p, const void *q)
{
return(strcmp(*(char **)p, *(char **)q));
}
static int
-glob1(pattern, pglob, limit)
- Char *pattern;
- glob_t *pglob;
- int *limit;
+glob1(Char *pattern, glob_t *pglob, int *limit)
{
Char pathbuf[MAXPATHLEN];
@@ -544,10 +526,8 @@ glob1(pattern, pglob, limit)
* meta characters.
*/
static int
-glob2(pathbuf, pathend, pathend_last, pattern, pglob, limit)
- Char *pathbuf, *pathend, *pathend_last, *pattern;
- glob_t *pglob;
- int *limit;
+glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
+ glob_t *pglob, int *limit)
{
struct stat sb;
Char *p, *q;
@@ -604,10 +584,8 @@ glob2(pathbuf, pathend, pathend_last, pattern, pglob, limit)
}
static int
-glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
- Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
- glob_t *pglob;
- int *limit;
+glob3(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
+ Char *restpattern, glob_t *pglob, int *limit)
{
struct dirent *dp;
DIR *dirp;
@@ -620,7 +598,7 @@ glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
* and dirent.h as taking pointers to differently typed opaque
* structures.
*/
- struct dirent *(*readdirfunc)();
+ struct dirent *(*readdirfunc)(void *);
if (pathend > pathend_last)
return (1);
@@ -645,7 +623,7 @@ glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
readdirfunc = pglob->gl_readdir;
else
- readdirfunc = readdir;
+ readdirfunc = (struct dirent *(*)(void *))readdir;
while ((dp = (*readdirfunc)(dirp))) {
u_char *sc;
Char *dc;
@@ -690,10 +668,7 @@ glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
*/
static int
-globextend(path, pglob, limit)
- const Char *path;
- glob_t *pglob;
- int *limit;
+globextend(const Char *path, glob_t *pglob, int *limit)
{
char **pathv;
int i;
@@ -745,8 +720,7 @@ globextend(path, pglob, limit)
* pattern causes a recursion level.
*/
static int
-match(name, pat, patend)
- Char *name, *pat, *patend;
+match(Char *name, Char *pat, Char *patend)
{
int ok, negate_range;
Char c, k;
@@ -797,8 +771,7 @@ match(name, pat, patend)
/* Free allocated data belonging to a glob_t structure. */
void
-globfree(pglob)
- glob_t *pglob;
+globfree(glob_t *pglob)
{
int i;
char **pp;
@@ -814,9 +787,7 @@ globfree(pglob)
}
static DIR *
-g_opendir(str, pglob)
- Char *str;
- glob_t *pglob;
+g_opendir(Char *str, glob_t *pglob)
{
char buf[MAXPATHLEN];
@@ -834,10 +805,7 @@ g_opendir(str, pglob)
}
static int
-g_lstat(fn, sb, pglob)
- Char *fn;
- struct stat *sb;
- glob_t *pglob;
+g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
{
char buf[MAXPATHLEN];
@@ -851,10 +819,7 @@ g_lstat(fn, sb, pglob)
}
static int
-g_stat(fn, sb, pglob)
- Char *fn;
- struct stat *sb;
- glob_t *pglob;
+g_stat(Char *fn, struct stat *sb, glob_t *pglob)
{
char buf[MAXPATHLEN];
@@ -868,9 +833,7 @@ g_stat(fn, sb, pglob)
}
static Char *
-g_strchr(str, ch)
- Char *str;
- int ch;
+g_strchr(Char *str, int ch)
{
do {
if (*str == ch)
@@ -880,10 +843,7 @@ g_strchr(str, ch)
}
static int
-g_Ctoc(str, buf, len)
- const Char *str;
- char *buf;
- u_int len;
+g_Ctoc(const Char *str, char *buf, u_int len)
{
while (len--) {
@@ -895,9 +855,7 @@ g_Ctoc(str, buf, len)
#ifdef DEBUG
static void
-qprintf(str, s)
- const char *str;
- Char *s;
+qprintf(const char *str, Char *s)
{
Char *p;
diff --git a/newlib/libc/posix/posix_spawn.c b/newlib/libc/posix/posix_spawn.c
index 46e4e53..51ad23f 100644
--- a/newlib/libc/posix/posix_spawn.c
+++ b/newlib/libc/posix/posix_spawn.c
@@ -102,56 +102,13 @@ Supporting OS subroutines required: <<_close>>, <<dup2>>, <<_fcntl>>,
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "posix_spawn.h"
/* Only deal with a pointer to environ, to work around subtle bugs with shared
libraries and/or small data systems where the user declares his own
'environ'. */
static char ***p_environ = &environ;
-struct __posix_spawnattr {
- short sa_flags;
- pid_t sa_pgroup;
- struct sched_param sa_schedparam;
- int sa_schedpolicy;
- sigset_t sa_sigdefault;
- sigset_t sa_sigmask;
-};
-
-struct __posix_spawn_file_actions {
- STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
-};
-
-typedef struct __posix_spawn_file_actions_entry {
- STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
- enum {
- FAE_OPEN,
- FAE_DUP2,
- FAE_CLOSE,
- FAE_CHDIR,
- FAE_FCHDIR
- } fae_action;
-
- int fae_fildes;
- union {
- struct {
- char *path;
-#define fae_path fae_data.open.path
- int oflag;
-#define fae_oflag fae_data.open.oflag
- mode_t mode;
-#define fae_mode fae_data.open.mode
- } open;
- struct {
- int newfildes;
-#define fae_newfildes fae_data.dup2.newfildes
- } dup2;
- char *dir;
-#define fae_dir fae_data.dir
- int dirfd;
-#define fae_dirfd fae_data.dirfd
- } fae_data;
-} posix_spawn_file_actions_entry_t;
-
/*
* Spawn routines
*/
diff --git a/newlib/libc/posix/posix_spawn.h b/newlib/libc/posix/posix_spawn.h
new file mode 100644
index 0000000..b4cad1e
--- /dev/null
+++ b/newlib/libc/posix/posix_spawn.h
@@ -0,0 +1,54 @@
+#ifndef _POSIX_SPAWN_H_
+#define _POSIX_SPAWN_H_
+
+#include <sys/cdefs.h>
+#include <sys/sched.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+struct __posix_spawnattr {
+ short sa_flags;
+ pid_t sa_pgroup;
+ struct sched_param sa_schedparam;
+ int sa_schedpolicy;
+ sigset_t sa_sigdefault;
+ sigset_t sa_sigmask;
+};
+
+struct __posix_spawn_file_actions {
+ STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
+};
+
+typedef struct __posix_spawn_file_actions_entry {
+ STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
+ enum {
+ FAE_OPEN,
+ FAE_DUP2,
+ FAE_CLOSE,
+ FAE_CHDIR,
+ FAE_FCHDIR
+ } fae_action;
+
+ int fae_fildes;
+ union {
+ struct {
+ char *path;
+#define fae_path fae_data.open.path
+ int oflag;
+#define fae_oflag fae_data.open.oflag
+ mode_t mode;
+#define fae_mode fae_data.open.mode
+ } open;
+ struct {
+ int newfildes;
+#define fae_newfildes fae_data.dup2.newfildes
+ } dup2;
+ char *dir;
+#define fae_dir fae_data.dir
+ int dirfd;
+#define fae_dirfd fae_data.dirfd
+ } fae_data;
+} posix_spawn_file_actions_entry_t;
+
+#endif /* !_POSIX_SPAWN_H_ */
diff --git a/newlib/libc/search/tdelete.c b/newlib/libc/search/tdelete.c
index a595200..b12158e 100644
--- a/newlib/libc/search/tdelete.c
+++ b/newlib/libc/search/tdelete.c
@@ -27,7 +27,7 @@ __RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
/* delete node with given key */
void *
tdelete (const void *__restrict vkey, /* key to be deleted */
- void **__restrict vrootp, /* address of the root of tree */
+ posix_tnode **__restrict vrootp,/* address of the root of tree */
int (*compar)(const void *, const void *))
{
node_t **rootp = (node_t **)vrootp;
diff --git a/newlib/libc/search/tfind.c b/newlib/libc/search/tfind.c
index 670f41f..8bebdac 100644
--- a/newlib/libc/search/tfind.c
+++ b/newlib/libc/search/tfind.c
@@ -26,7 +26,7 @@ __RCSID("$NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
/* find a node, or return 0 */
void *
tfind (const void *vkey, /* key to be found */
- void **vrootp, /* address of the tree root */
+ posix_tnode *const *vrootp, /* address of the tree root */
int (*compar)(const void *, const void *))
{
node_t **rootp = (node_t **)vrootp;
diff --git a/newlib/libc/search/tsearch.c b/newlib/libc/search/tsearch.c
index 82d6944..9be77f1 100644
--- a/newlib/libc/search/tsearch.c
+++ b/newlib/libc/search/tsearch.c
@@ -26,7 +26,7 @@ __RCSID("$NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $");
/* find or insert datum into search tree */
void *
tsearch (const void *vkey, /* key to be located */
- void **vrootp, /* address of tree root */
+ posix_tnode **vrootp, /* address of tree root */
int (*compar)(const void *, const void *))
{
node_t *q;
diff --git a/newlib/libc/search/twalk.c b/newlib/libc/search/twalk.c
index 7aec6e4..26d037a 100644
--- a/newlib/libc/search/twalk.c
+++ b/newlib/libc/search/twalk.c
@@ -50,8 +50,8 @@ trecurse(
/* Walk the nodes of a tree */
void
-twalk (const void *vroot, /* Root of the tree to be walked */
- void (*action)(const void *, VISIT, int))
+twalk (const posix_tnode *vroot,/* Root of the tree to be walked */
+ void (*action)(const posix_tnode *, VISIT, int))
{
if (vroot != NULL && action != NULL)
trecurse(vroot, action, 0);
diff --git a/newlib/libc/stdlib/mbtowc_r.c b/newlib/libc/stdlib/mbtowc_r.c
index cab8333..6c3bd3d 100644
--- a/newlib/libc/stdlib/mbtowc_r.c
+++ b/newlib/libc/stdlib/mbtowc_r.c
@@ -677,6 +677,21 @@ __utf8_mbtowc (struct _reent *r,
state->__count = 3;
else if (n < (size_t)-1)
++n;
+ if (n < 4)
+ return -2;
+ ch = t[i++];
+ if (ch < 0x80 || ch > 0xbf)
+ {
+ _REENT_ERRNO(r) = EILSEQ;
+ return -1;
+ }
+ /* Note: Originally we created the low surrogate pair on systems with
+ wchar_t == UTF-16 *before* checking the 4th byte. This was utterly
+ wrong, because this failed to check the last byte for being a valid
+ value for a complete UTF-8 4 byte sequence. As a result, calling
+ functions happily digested the low surrogate and then got an entirely
+ different character and handled this separately, thus generating
+ invalid UTF-16 values. */
if (state->__count == 3 && sizeof(wchar_t) == 2)
{
/* On systems which have wchar_t being UTF-16 values, the value
@@ -695,15 +710,7 @@ __utf8_mbtowc (struct _reent *r,
| (wint_t)((state->__value.__wchb[2] & 0x3f) << 6);
state->__count = 4;
*pwc = 0xd800 | ((tmp - 0x10000) >> 10);
- return i;
- }
- if (n < 4)
- return -2;
- ch = t[i++];
- if (ch < 0x80 || ch > 0xbf)
- {
- _REENT_ERRNO(r) = EILSEQ;
- return -1;
+ return 3;
}
tmp = (wint_t)((state->__value.__wchb[0] & 0x07) << 18)
| (wint_t)((state->__value.__wchb[1] & 0x3f) << 12)
diff --git a/newlib/libc/stdlib/wcstombs_r.c b/newlib/libc/stdlib/wcstombs_r.c
index c6a06a3..2c82a2c 100644
--- a/newlib/libc/stdlib/wcstombs_r.c
+++ b/newlib/libc/stdlib/wcstombs_r.c
@@ -17,14 +17,15 @@ _wcstombs_r (struct _reent *r,
if (s == NULL)
{
size_t num_bytes = 0;
- while (*pwcs != 0)
+ do
{
- bytes = __WCTOMB (r, buff, *pwcs++, state);
+ bytes = __WCTOMB (r, buff, *pwcs, state);
if (bytes == -1)
return -1;
num_bytes += bytes;
}
- return num_bytes;
+ while (*pwcs++ != 0x00);
+ return num_bytes - 1;
}
else
{
diff --git a/newlib/libc/stdlib/wctomb_r.c b/newlib/libc/stdlib/wctomb_r.c
index 5ea1e13..ec6adfa 100644
--- a/newlib/libc/stdlib/wctomb_r.c
+++ b/newlib/libc/stdlib/wctomb_r.c
@@ -62,8 +62,8 @@ __utf8_wctomb (struct _reent *r,
of the surrogate and proceed to convert the given character. Note
to return extra 3 bytes. */
wchar_t tmp;
- tmp = (state->__value.__wchb[0] << 16 | state->__value.__wchb[1] << 8)
- - (0x10000 >> 10 | 0xd80d);
+ tmp = (((state->__value.__wchb[0] << 16 | state->__value.__wchb[1] << 8)
+ - 0x10000) >> 10) | 0xd800;
*s++ = 0xe0 | ((tmp & 0xf000) >> 12);
*s++ = 0x80 | ((tmp & 0xfc0) >> 6);
*s++ = 0x80 | (tmp & 0x3f);
diff --git a/newlib/libc/sys/rtems/include/limits.h b/newlib/libc/sys/rtems/include/limits.h
index 5e71e4b..8dbf88b 100644
--- a/newlib/libc/sys/rtems/include/limits.h
+++ b/newlib/libc/sys/rtems/include/limits.h
@@ -56,12 +56,14 @@
#define _POSIX_TZNAME_MAX 3
/*
- * Definitions of the following may be omitted if the value is >= stated
- * minimum but is indeterminate.
+ * Definitions of the following may be omitted if the value is >= stated
+ * minimum but is indeterminate. The following are not defined because
+ * RTEMS does not have an inherent limit.
+ *
+ * - AIO_LISTIO_MAX
+ * - AIO_MAX
*/
-#define AIO_LISTIO_MAX 2
-#define AIO_MAX 1
#define AIO_PRIO_DELTA_MAX 0
#define DELAYTIMER_MAX 32
#define MQ_OPEN_MAX 8
diff --git a/newlib/libc/sys/rtems/include/semaphore.h b/newlib/libc/sys/rtems/include/semaphore.h
index 939135f..6d756d5 100644
--- a/newlib/libc/sys/rtems/include/semaphore.h
+++ b/newlib/libc/sys/rtems/include/semaphore.h
@@ -55,6 +55,12 @@ int sem_timedwait(sem_t * __restrict, const struct timespec * __restrict);
int sem_trywait(sem_t *);
int sem_unlink(const char *);
int sem_wait(sem_t *);
+
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
+int sem_clockwait(sem_t * __restrict, __clockid_t,
+ const struct timespec * __restrict);
+#endif /* __GNU_VISIBLE || __POSIX_VISIBLE >= 202405 */
+
__END_DECLS
#endif /* !_SEMAPHORE_H_ */
diff --git a/newlib/libc/sys/rtems/include/sys/dirent.h b/newlib/libc/sys/rtems/include/sys/dirent.h
index 6f8ff42..3e41635 100644
--- a/newlib/libc/sys/rtems/include/sys/dirent.h
+++ b/newlib/libc/sys/rtems/include/sys/dirent.h
@@ -99,7 +99,7 @@ struct dirent {
#define __dirfd(dp) ((dp)->dd_fd)
-#if __BSD_VISIBLE
+#if __BSD_VISIBLE || __POSIX_VISIBLE >= 202405
/*
* File types
diff --git a/newlib/libc/sys/rtems/include/sys/poll.h b/newlib/libc/sys/rtems/include/sys/poll.h
index cc6ad49..fd2f14d 100644
--- a/newlib/libc/sys/rtems/include/sys/poll.h
+++ b/newlib/libc/sys/rtems/include/sys/poll.h
@@ -35,6 +35,10 @@
#include <sys/cdefs.h>
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
+#include <signal.h>
+#endif
+
/*
* This file is intended to be compatible with the traditional poll.h.
*/
@@ -100,6 +104,11 @@ struct pollfd {
__BEGIN_DECLS
int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout);
+#if (__GNU_VISIBLE || __POSIX_VISIBLE >= 202405)
+int ppoll(struct pollfd _pfd[], nfds_t _nfds,
+ const struct timespec *__restrict _timeout,
+ const sigset_t *__restrict _newsigmask);
+#endif /* __GNU_VISIBLE || __POSIX_VISIBLE >= 202405 */
__END_DECLS
#endif /* !_KERNEL */