[libc-commits] [libc] draft: libc support for hexagon linux (PR #81815)
Brian Cain via libc-commits
libc-commits at lists.llvm.org
Wed Feb 14 18:04:46 PST 2024
https://github.com/androm3da created https://github.com/llvm/llvm-project/pull/81815
<this PR not in a useful state for review>
>From 1d83962f70c2a28dc5c77d00cd2a099d28923469 Mon Sep 17 00:00:00 2001
From: Brian Cain <bcain at quicinc.com>
Date: Sat, 16 Sep 2023 15:21:03 -0700
Subject: [PATCH 1/4] [libc] Add support for hexagon architecture,
hexagon-linux
The start.cpp is a WIP, might make sense to abstract some of the commonalities
among hexagon and x86_64?
The sin, cos, tan entrypoints are omitted to avoid a build error. I think we
might need a target-independent implementation of these?
---
.../cmake/modules/LLVMLibCArchitectures.cmake | 4 +
libc/config/linux/app.h | 6 +-
libc/config/linux/hexagon/entrypoints.txt | 543 ++++++++++++++++++
libc/config/linux/hexagon/headers.txt | 41 ++
.../llvm-libc-macros/linux/signal-macros.h | 2 +-
libc/include/llvm-libc-types/fenv_t.h | 2 +
libc/include/llvm-libc-types/jmp_buf.h | 3 +
.../OSUtil/linux/hexagon/CMakeLists.txt | 8 +
.../__support/OSUtil/linux/hexagon/syscall.h | 112 ++++
libc/src/__support/OSUtil/linux/syscall.h | 2 +
libc/src/__support/RPC/rpc_util.h | 2 +
.../macros/properties/architectures.h | 4 +
libc/src/__support/macros/properties/float.h | 3 +-
libc/src/__support/threads/linux/thread.cpp | 4 +-
libc/src/__support/threads/thread.h | 2 +
libc/src/setjmp/hexagon/CMakeLists.txt | 25 +
libc/src/setjmp/hexagon/longjmp.cpp | 37 ++
libc/src/setjmp/hexagon/setjmp.cpp | 36 ++
libc/src/string/memory_utils/inline_bcmp.h | 3 +-
libc/src/string/memory_utils/inline_memcmp.h | 3 +-
libc/src/string/memory_utils/inline_memcpy.h | 2 +-
libc/src/string/memory_utils/inline_memmove.h | 2 +-
libc/src/string/memory_utils/inline_memset.h | 2 +-
libc/startup/linux/hexagon/CMakeLists.txt | 18 +
libc/startup/linux/hexagon/start.cpp | 235 ++++++++
25 files changed, 1091 insertions(+), 10 deletions(-)
create mode 100644 libc/config/linux/hexagon/entrypoints.txt
create mode 100644 libc/config/linux/hexagon/headers.txt
create mode 100644 libc/src/__support/OSUtil/linux/hexagon/CMakeLists.txt
create mode 100644 libc/src/__support/OSUtil/linux/hexagon/syscall.h
create mode 100644 libc/src/setjmp/hexagon/CMakeLists.txt
create mode 100644 libc/src/setjmp/hexagon/longjmp.cpp
create mode 100644 libc/src/setjmp/hexagon/setjmp.cpp
create mode 100644 libc/startup/linux/hexagon/CMakeLists.txt
create mode 100644 libc/startup/linux/hexagon/start.cpp
diff --git a/libc/cmake/modules/LLVMLibCArchitectures.cmake b/libc/cmake/modules/LLVMLibCArchitectures.cmake
index 10571101a34178..de223ce52963ed 100644
--- a/libc/cmake/modules/LLVMLibCArchitectures.cmake
+++ b/libc/cmake/modules/LLVMLibCArchitectures.cmake
@@ -59,6 +59,8 @@ function(get_arch_and_system_from_triple triple arch_var sys_var)
set(target_arch "riscv32")
elseif(target_arch MATCHES "^riscv64")
set(target_arch "riscv64")
+ elseif(target_arch MATCHES "^hexagon")
+ set(target_arch "hexagon")
else()
return()
endif()
@@ -156,6 +158,8 @@ elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "riscv64")
elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "riscv32")
set(LIBC_TARGET_ARCHITECTURE_IS_RISCV32 TRUE)
set(LIBC_TARGET_ARCHITECTURE "riscv")
+elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "hexagon")
+ set(LIBC_TARGET_ARCHITECTURE_IS_HEXAGON TRUE)
else()
message(FATAL_ERROR
"Unsupported libc target architecture ${LIBC_TARGET_ARCHITECTURE}")
diff --git a/libc/config/linux/app.h b/libc/config/linux/app.h
index b17026a7832a3c..dcbac7ed44a94f 100644
--- a/libc/config/linux/app.h
+++ b/libc/config/linux/app.h
@@ -37,11 +37,13 @@ struct TLSImage {
#if defined(LIBC_TARGET_ARCH_IS_X86_64) || \
defined(LIBC_TARGET_ARCH_IS_AARCH64) || \
- defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
+ defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) || \
+ defined(LIBC_TARGET_ARCH_IS_HEXAGON)
// At the language level, argc is an int. But we use uint64_t as the x86_64
// ABI specifies it as an 8 byte value. Likewise, in the ARM64 ABI, arguments
// are usually passed in registers. x0 is a doubleword register, so this is
-// 64 bit for aarch64 as well.
+// 64 bit for aarch64 as well. For hexagon, argc is an int and uintptr_t
+// is 32-bits so the size will correspond.
typedef uintptr_t ArgcType;
// At the language level, argv is a char** value. However, we use uint64_t as
diff --git a/libc/config/linux/hexagon/entrypoints.txt b/libc/config/linux/hexagon/entrypoints.txt
new file mode 100644
index 00000000000000..053667edf6d866
--- /dev/null
+++ b/libc/config/linux/hexagon/entrypoints.txt
@@ -0,0 +1,543 @@
+set(TARGET_LIBC_ENTRYPOINTS
+ # ctype.h entrypoints
+ libc.src.ctype.isalnum
+ libc.src.ctype.isalpha
+ libc.src.ctype.isascii
+ libc.src.ctype.isblank
+ libc.src.ctype.iscntrl
+ libc.src.ctype.isdigit
+ libc.src.ctype.isgraph
+ libc.src.ctype.islower
+ libc.src.ctype.isprint
+ libc.src.ctype.ispunct
+ libc.src.ctype.isspace
+ libc.src.ctype.isupper
+ libc.src.ctype.isxdigit
+ libc.src.ctype.toascii
+ libc.src.ctype.tolower
+ libc.src.ctype.toupper
+
+ # errno.h entrypoints
+ libc.src.errno.errno
+
+ # fcntl.h entrypoints
+ libc.src.fcntl.creat
+ libc.src.fcntl.open
+ libc.src.fcntl.openat
+
+ # sched.h entrypoints
+ libc.src.sched.sched_get_priority_max
+ libc.src.sched.sched_get_priority_min
+ libc.src.sched.sched_getaffinity
+ libc.src.sched.sched_getparam
+ libc.src.sched.sched_getscheduler
+ libc.src.sched.sched_rr_get_interval
+ libc.src.sched.sched_setaffinity
+ libc.src.sched.sched_setparam
+ libc.src.sched.sched_setscheduler
+ libc.src.sched.sched_yield
+
+ # string.h entrypoints
+ libc.src.string.bcmp
+ libc.src.string.bcopy
+ libc.src.string.bzero
+ libc.src.string.index
+ libc.src.string.memccpy
+ libc.src.string.memchr
+ libc.src.string.memcmp
+ libc.src.string.memcpy
+ libc.src.string.memmem
+ libc.src.string.memmove
+ libc.src.string.mempcpy
+ libc.src.string.memrchr
+ libc.src.string.memset
+ libc.src.string.rindex
+ libc.src.string.stpcpy
+ libc.src.string.stpncpy
+ libc.src.string.strcasecmp
+ libc.src.string.strcasestr
+ libc.src.string.strcat
+ libc.src.string.strchr
+ libc.src.string.strchrnul
+ libc.src.string.strcmp
+ libc.src.string.strcoll
+ libc.src.string.strcpy
+ libc.src.string.strcspn
+ libc.src.string.strdup
+ libc.src.string.strerror
+ libc.src.string.strerror_r
+ libc.src.string.strlcat
+ libc.src.string.strlcpy
+ libc.src.string.strlen
+ libc.src.string.strncasecmp
+ libc.src.string.strncat
+ libc.src.string.strncmp
+ libc.src.string.strncpy
+ libc.src.string.strndup
+ libc.src.string.strnlen
+ libc.src.string.strpbrk
+ libc.src.string.strrchr
+ libc.src.string.strsep
+ libc.src.string.strsignal
+ libc.src.string.strspn
+ libc.src.string.strstr
+ libc.src.string.strtok
+ libc.src.string.strtok_r
+ libc.src.string.strxfrm
+
+ # inttypes.h entrypoints
+ libc.src.inttypes.imaxabs
+ libc.src.inttypes.imaxdiv
+ libc.src.inttypes.strtoimax
+ libc.src.inttypes.strtoumax
+
+ # stdlib.h entrypoints
+ libc.src.stdlib.abs
+ libc.src.stdlib.atoi
+ libc.src.stdlib.atof
+ libc.src.stdlib.atol
+ libc.src.stdlib.atoll
+ libc.src.stdlib.bsearch
+ libc.src.stdlib.div
+ libc.src.stdlib.labs
+ libc.src.stdlib.ldiv
+ libc.src.stdlib.llabs
+ libc.src.stdlib.lldiv
+ libc.src.stdlib.qsort
+ libc.src.stdlib.qsort_r
+ libc.src.stdlib.rand
+ libc.src.stdlib.srand
+ libc.src.stdlib.strtod
+ libc.src.stdlib.strtof
+ libc.src.stdlib.strtol
+ libc.src.stdlib.strtold
+ libc.src.stdlib.strtoll
+ libc.src.stdlib.strtoul
+ libc.src.stdlib.strtoull
+
+ # stdlib.h external entrypoints
+ libc.src.stdlib.malloc
+ libc.src.stdlib.calloc
+ libc.src.stdlib.realloc
+ libc.src.stdlib.aligned_alloc
+ libc.src.stdlib.free
+
+ # stdio.h entrypoints
+ libc.src.stdio.remove
+ libc.src.stdio.sprintf
+ libc.src.stdio.snprintf
+ libc.src.stdio.fprintf
+ libc.src.stdio.printf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vsnprintf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vprintf
+
+ # sys/mman.h entrypoints
+ libc.src.sys.mman.madvise
+ libc.src.sys.mman.mmap
+ libc.src.sys.mman.mprotect
+ libc.src.sys.mman.munmap
+ libc.src.sys.mman.posix_madvise
+
+ # sys/random.h entrypoints
+ libc.src.sys.random.getrandom
+
+ # sys/resource.h entrypoints
+ libc.src.sys.resource.getrlimit
+ libc.src.sys.resource.setrlimit
+
+ # sys/sendfile entrypoints
+ libc.src.sys.sendfile.sendfile
+
+ # sys/socket.h entrypoints
+ libc.src.sys.socket.socket
+
+ # sys/stat.h entrypoints
+ libc.src.sys.stat.chmod
+ libc.src.sys.stat.fchmod
+ libc.src.sys.stat.fchmodat
+ libc.src.sys.stat.fstat
+ libc.src.sys.stat.lstat
+ libc.src.sys.stat.mkdir
+ libc.src.sys.stat.mkdirat
+ libc.src.sys.stat.stat
+
+ # sys/utsname.h entrypoints
+ libc.src.sys.utsname.uname
+
+ # sys/wait.h entrypoints
+ libc.src.sys.wait.wait
+ libc.src.sys.wait.wait4
+ libc.src.sys.wait.waitpid
+
+ # termios.h entrypoints
+ libc.src.termios.cfgetispeed
+ libc.src.termios.cfgetospeed
+ libc.src.termios.cfsetispeed
+ libc.src.termios.cfsetospeed
+ libc.src.termios.tcgetattr
+ libc.src.termios.tcgetsid
+ libc.src.termios.tcdrain
+ libc.src.termios.tcflow
+ libc.src.termios.tcflush
+ libc.src.termios.tcsendbreak
+ libc.src.termios.tcsetattr
+
+ # unistd.h entrypoints
+ libc.src.unistd.access
+ libc.src.unistd.chdir
+ libc.src.unistd.close
+ libc.src.unistd.dup
+ libc.src.unistd.dup2
+ libc.src.unistd.dup3
+ libc.src.unistd.execve
+ libc.src.unistd.fchdir
+ libc.src.unistd.fsync
+ libc.src.unistd.ftruncate
+ libc.src.unistd.getcwd
+ libc.src.unistd.geteuid
+ libc.src.unistd.getpid
+ libc.src.unistd.getppid
+ libc.src.unistd.getuid
+ libc.src.unistd.isatty
+ libc.src.unistd.link
+ libc.src.unistd.linkat
+ libc.src.unistd.lseek
+ libc.src.unistd.pread
+ libc.src.unistd.pwrite
+ libc.src.unistd.read
+ libc.src.unistd.readlink
+ libc.src.unistd.readlinkat
+ libc.src.unistd.rmdir
+ libc.src.unistd.symlink
+ libc.src.unistd.symlinkat
+ libc.src.unistd.sysconf
+ libc.src.unistd.truncate
+ libc.src.unistd.unlink
+ libc.src.unistd.unlinkat
+ libc.src.unistd.write
+
+ # wchar.h entrypoints
+ libc.src.wchar.wctob
+)
+
+set(TARGET_LIBM_ENTRYPOINTS
+ # fenv.h entrypoints
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.fedisableexcept
+ libc.src.fenv.feenableexcept
+ libc.src.fenv.fegetenv
+ libc.src.fenv.fegetexcept
+ libc.src.fenv.fegetexceptflag
+ libc.src.fenv.fegetround
+ libc.src.fenv.feholdexcept
+ libc.src.fenv.fesetenv
+ libc.src.fenv.fesetexceptflag
+ libc.src.fenv.fesetround
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fetestexcept
+ libc.src.fenv.feupdateenv
+
+ # math.h entrypoints
+ libc.src.math.acosf
+ libc.src.math.acoshf
+ libc.src.math.asinf
+ libc.src.math.asinhf
+ libc.src.math.atanf
+ libc.src.math.atanhf
+ libc.src.math.copysign
+ libc.src.math.copysignf
+ libc.src.math.copysignl
+ libc.src.math.ceil
+ libc.src.math.ceilf
+ libc.src.math.ceill
+ #libc.src.math.cos FIXME
+ libc.src.math.coshf
+ libc.src.math.cosf
+ libc.src.math.erff
+ libc.src.math.exp
+ libc.src.math.expf
+ libc.src.math.exp10
+ libc.src.math.exp10f
+ libc.src.math.exp2
+ libc.src.math.exp2f
+ libc.src.math.expm1f
+ libc.src.math.fabs
+ libc.src.math.fabsf
+ libc.src.math.fabsl
+ libc.src.math.fdim
+ libc.src.math.fdimf
+ libc.src.math.fdiml
+ libc.src.math.floor
+ libc.src.math.floorf
+ libc.src.math.floorl
+ libc.src.math.fma
+ libc.src.math.fmaf
+ libc.src.math.fmin
+ libc.src.math.fminf
+ libc.src.math.fminl
+ libc.src.math.fmax
+ libc.src.math.fmaxf
+ libc.src.math.fmaxl
+ libc.src.math.fmod
+ libc.src.math.fmodf
+ libc.src.math.frexp
+ libc.src.math.frexpf
+ libc.src.math.frexpl
+ libc.src.math.hypot
+ libc.src.math.hypotf
+ libc.src.math.ilogb
+ libc.src.math.ilogbf
+ libc.src.math.ilogbl
+ libc.src.math.ldexp
+ libc.src.math.ldexpf
+ libc.src.math.ldexpl
+ libc.src.math.llrint
+ libc.src.math.llrintf
+ libc.src.math.llrintl
+ libc.src.math.llround
+ libc.src.math.llroundf
+ libc.src.math.llroundl
+ libc.src.math.log10
+ libc.src.math.log10f
+ libc.src.math.log1p
+ libc.src.math.log1pf
+ libc.src.math.log2
+ libc.src.math.log2f
+ libc.src.math.log
+ libc.src.math.logf
+ libc.src.math.logb
+ libc.src.math.logbf
+ libc.src.math.logbl
+ libc.src.math.lrint
+ libc.src.math.lrintf
+ libc.src.math.lrintl
+ libc.src.math.lround
+ libc.src.math.lroundf
+ libc.src.math.lroundl
+ libc.src.math.modf
+ libc.src.math.modff
+ libc.src.math.modfl
+ libc.src.math.nearbyint
+ libc.src.math.nearbyintf
+ libc.src.math.nearbyintl
+ libc.src.math.nextafter
+ libc.src.math.nextafterf
+ libc.src.math.nextafterl
+ libc.src.math.remainderf
+ libc.src.math.remainder
+ libc.src.math.remainderl
+ libc.src.math.remquof
+ libc.src.math.remquo
+ libc.src.math.remquol
+ libc.src.math.rint
+ libc.src.math.rintf
+ libc.src.math.rintl
+ libc.src.math.round
+ libc.src.math.roundf
+ libc.src.math.roundl
+ libc.src.math.scalbn
+ libc.src.math.scalbnf
+ libc.src.math.scalbnl
+ #libc.src.math.sin FIXME
+ libc.src.math.sincosf
+ libc.src.math.sinhf
+ libc.src.math.sinf
+ libc.src.math.sqrt
+ libc.src.math.sqrtf
+ libc.src.math.sqrtl
+ #libc.src.math.tan FIXME
+ libc.src.math.tanf
+ libc.src.math.tanhf
+ libc.src.math.trunc
+ libc.src.math.truncf
+ libc.src.math.truncl
+)
+
+if(LLVM_LIBC_FULL_BUILD)
+ list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # assert.h entrypoints
+ libc.src.assert.__assert_fail
+
+ # dirent.h entrypoints
+ libc.src.dirent.closedir
+ libc.src.dirent.dirfd
+ libc.src.dirent.opendir
+ libc.src.dirent.readdir
+
+ # network.h entrypoints
+ libc.src.network.htonl
+ libc.src.network.htons
+ libc.src.network.ntohl
+ libc.src.network.ntohs
+
+ # pthread.h entrypoints
+ libc.src.pthread.pthread_atfork
+ libc.src.pthread.pthread_attr_destroy
+ libc.src.pthread.pthread_attr_init
+ libc.src.pthread.pthread_attr_getdetachstate
+ libc.src.pthread.pthread_attr_getguardsize
+ libc.src.pthread.pthread_attr_getstack
+ libc.src.pthread.pthread_attr_getstacksize
+ libc.src.pthread.pthread_attr_setdetachstate
+ libc.src.pthread.pthread_attr_setguardsize
+ libc.src.pthread.pthread_attr_setstack
+ libc.src.pthread.pthread_attr_setstacksize
+ libc.src.pthread.pthread_create
+ libc.src.pthread.pthread_detach
+ libc.src.pthread.pthread_equal
+ libc.src.pthread.pthread_exit
+ libc.src.pthread.pthread_getname_np
+ libc.src.pthread.pthread_getspecific
+ libc.src.pthread.pthread_join
+ libc.src.pthread.pthread_key_create
+ libc.src.pthread.pthread_key_delete
+ libc.src.pthread.pthread_self
+ libc.src.pthread.pthread_setname_np
+ libc.src.pthread.pthread_mutex_destroy
+ libc.src.pthread.pthread_mutex_init
+ libc.src.pthread.pthread_mutex_lock
+ libc.src.pthread.pthread_mutex_unlock
+ libc.src.pthread.pthread_mutexattr_destroy
+ libc.src.pthread.pthread_mutexattr_init
+ libc.src.pthread.pthread_mutexattr_getpshared
+ libc.src.pthread.pthread_mutexattr_getrobust
+ libc.src.pthread.pthread_mutexattr_gettype
+ libc.src.pthread.pthread_mutexattr_setpshared
+ libc.src.pthread.pthread_mutexattr_setrobust
+ libc.src.pthread.pthread_mutexattr_settype
+ libc.src.pthread.pthread_once
+ libc.src.pthread.pthread_setspecific
+
+ # sched.h entrypoints
+ libc.src.sched.__sched_getcpucount
+
+ # setjmp.h entrypoints
+ libc.src.setjmp.longjmp
+ libc.src.setjmp.setjmp
+
+ # stdio.h entrypoints
+ libc.src.stdio.clearerr
+ libc.src.stdio.clearerr_unlocked
+ libc.src.stdio.fclose
+ libc.src.stdio.flockfile
+ libc.src.stdio.feof
+ libc.src.stdio.feof_unlocked
+ libc.src.stdio.ferror
+ libc.src.stdio.ferror_unlocked
+ libc.src.stdio.fgetc
+ libc.src.stdio.fgetc_unlocked
+ libc.src.stdio.fgets
+ libc.src.stdio.fflush
+ libc.src.stdio.fopen
+ libc.src.stdio.fputc
+ libc.src.stdio.fputs
+ libc.src.stdio.fopencookie
+ libc.src.stdio.fread
+ libc.src.stdio.fread_unlocked
+ libc.src.stdio.fseek
+ libc.src.stdio.ftell
+ libc.src.stdio.funlockfile
+ libc.src.stdio.fwrite
+ libc.src.stdio.fwrite_unlocked
+ libc.src.stdio.getc
+ libc.src.stdio.getc_unlocked
+ libc.src.stdio.getchar
+ libc.src.stdio.getchar_unlocked
+ libc.src.stdio.sscanf
+ libc.src.stdio.scanf
+ libc.src.stdio.fscanf
+ libc.src.stdio.putc
+ libc.src.stdio.putchar
+ libc.src.stdio.puts
+ libc.src.stdio.setbuf
+ libc.src.stdio.setvbuf
+ libc.src.stdio.stderr
+ libc.src.stdio.stdin
+ libc.src.stdio.stdout
+ libc.src.stdio.ungetc
+
+ # stdlib.h entrypoints
+ libc.src.stdlib._Exit
+ libc.src.stdlib.abort
+ libc.src.stdlib.atexit
+ libc.src.stdlib.exit
+ libc.src.stdlib.getenv
+
+ # signal.h entrypoints
+ libc.src.signal.raise
+ libc.src.signal.kill
+ libc.src.signal.sigaction
+ libc.src.signal.sigaltstack
+ libc.src.signal.sigdelset
+ libc.src.signal.sigaddset
+ libc.src.signal.sigemptyset
+ libc.src.signal.sigprocmask
+ libc.src.signal.sigfillset
+ libc.src.signal.signal
+
+ # spawn.h entrypoints
+ libc.src.spawn.posix_spawn
+ libc.src.spawn.posix_spawn_file_actions_addclose
+ libc.src.spawn.posix_spawn_file_actions_adddup2
+ libc.src.spawn.posix_spawn_file_actions_addopen
+ libc.src.spawn.posix_spawn_file_actions_destroy
+ libc.src.spawn.posix_spawn_file_actions_init
+
+ # threads.h entrypoints
+ libc.src.threads.call_once
+ libc.src.threads.cnd_broadcast
+ libc.src.threads.cnd_destroy
+ libc.src.threads.cnd_init
+ libc.src.threads.cnd_signal
+ libc.src.threads.cnd_wait
+ libc.src.threads.mtx_destroy
+ libc.src.threads.mtx_init
+ libc.src.threads.mtx_lock
+ libc.src.threads.mtx_unlock
+ libc.src.threads.thrd_create
+ libc.src.threads.thrd_current
+ libc.src.threads.thrd_detach
+ libc.src.threads.thrd_equal
+ libc.src.threads.thrd_exit
+ libc.src.threads.thrd_join
+ libc.src.threads.tss_create
+ libc.src.threads.tss_delete
+ libc.src.threads.tss_get
+ libc.src.threads.tss_set
+
+ # time.h entrypoints
+ libc.src.time.asctime
+ libc.src.time.asctime_r
+ libc.src.time.clock_gettime
+ libc.src.time.clock
+ libc.src.time.difftime
+ libc.src.time.gettimeofday
+ libc.src.time.gmtime
+ libc.src.time.gmtime_r
+ libc.src.time.mktime
+ libc.src.time.nanosleep
+ libc.src.time.time
+
+ # unistd.h entrypoints
+ libc.src.unistd.environ
+ libc.src.unistd.execv
+ libc.src.unistd.fork
+ libc.src.unistd.__llvm_libc_syscall
+ libc.src.unistd.getopt
+ libc.src.unistd.optarg
+ libc.src.unistd.optind
+ libc.src.unistd.optopt
+ libc.src.unistd.opterr
+ libc.src.unistd.swab
+
+ # sys/select.h entrypoints
+ libc.src.sys.select.select
+ )
+endif()
+
+set(TARGET_LLVMLIBC_ENTRYPOINTS
+ ${TARGET_LIBC_ENTRYPOINTS}
+ ${TARGET_LIBM_ENTRYPOINTS}
+)
diff --git a/libc/config/linux/hexagon/headers.txt b/libc/config/linux/hexagon/headers.txt
new file mode 100644
index 00000000000000..aaa75a9dd08cbd
--- /dev/null
+++ b/libc/config/linux/hexagon/headers.txt
@@ -0,0 +1,41 @@
+set(TARGET_PUBLIC_HEADERS
+ libc.include.assert
+ libc.include.ctype
+ libc.include.dirent
+ libc.include.errno
+ libc.include.fcntl
+ libc.include.fenv
+ libc.include.inttypes
+ libc.include.math
+ libc.include.pthread
+ libc.include.sched
+ libc.include.signal
+ libc.include.spawn
+ libc.include.setjmp
+ libc.include.stdio
+ libc.include.stdlib
+ libc.include.string
+ libc.include.strings
+ libc.include.termios
+ libc.include.threads
+ libc.include.time
+ libc.include.unistd
+ libc.include.wchar
+
+ libc.include.arpa_inet
+
+ libc.include.sys_auxv
+ libc.include.sys_ioctl
+ libc.include.sys_mman
+ libc.include.sys_prctl
+ libc.include.sys_random
+ libc.include.sys_resource
+ libc.include.sys_select
+ libc.include.sys_socket
+ libc.include.sys_stat
+ libc.include.sys_syscall
+ libc.include.sys_time
+ libc.include.sys_types
+ libc.include.sys_utsname
+ libc.include.sys_wait
+)
diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h
index deb190ec375998..1182544713f36e 100644
--- a/libc/include/llvm-libc-macros/linux/signal-macros.h
+++ b/libc/include/llvm-libc-macros/linux/signal-macros.h
@@ -82,7 +82,7 @@
#elif defined(__aarch64__)
#define MINSIGSTKSZ 5120
#define SIGSTKSZ 16384
-#elif defined(__riscv)
+#elif defined(__riscv) || defined(__hexagon__)
#define MINSIGSTKSZ 2048
#define SIGSTKSZ 8192
#else
diff --git a/libc/include/llvm-libc-types/fenv_t.h b/libc/include/llvm-libc-types/fenv_t.h
index 86fcf2e49a7fff..6b096e23378aa1 100644
--- a/libc/include/llvm-libc-types/fenv_t.h
+++ b/libc/include/llvm-libc-types/fenv_t.h
@@ -25,6 +25,8 @@ typedef struct {
} fenv_t;
#elif defined(__riscv)
typedef unsigned int fenv_t;
+#elif defined(__hexagon__)
+typedef unsigned int fenv_t;
#elif defined(__AMDGPU__) || defined(__NVPTX__)
typedef struct {
unsigned int __fpc;
diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index 6af4e8ebad92ca..f619759de3e81d 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -32,6 +32,9 @@ typedef struct {
#elif defined(__riscv_float_abi_single)
#error "__jmp_buf not available for your target architecture."
#endif
+#elif defined(__hexagon__)
+ /* Callee-saved registers. */
+ long int __regs[16];
#else
#error "__jmp_buf not available for your target architecture."
#endif
diff --git a/libc/src/__support/OSUtil/linux/hexagon/CMakeLists.txt b/libc/src/__support/OSUtil/linux/hexagon/CMakeLists.txt
new file mode 100644
index 00000000000000..e2988d33cec2f6
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/hexagon/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_header_library(
+ linux_hexagon_util
+ HDRS
+ syscall.h
+ DEPENDS
+ libc.src.__support.common
+)
+
diff --git a/libc/src/__support/OSUtil/linux/hexagon/syscall.h b/libc/src/__support/OSUtil/linux/hexagon/syscall.h
new file mode 100644
index 00000000000000..3f1a609c8c6acc
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/hexagon/syscall.h
@@ -0,0 +1,112 @@
+//===--------- inline implementation of hexagon syscalls ----------* C++ *-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_OSUTIL_LINUX_HEXAGON_SYSCALL_H
+#define LLVM_LIBC_SRC_SUPPORT_OSUTIL_LINUX_HEXAGON_SYSCALL_H
+
+#include "src/__support/common.h"
+
+#define REGISTER_DECL_0 \
+ register long r6 __asm__("r6") = number; \
+ register long r0 __asm__("r0");
+#define REGISTER_DECL_1 \
+ register long r6 __asm__("r6") = number; \
+ register long r0 __asm__("r0") = arg1;
+#define REGISTER_DECL_2 \
+ REGISTER_DECL_1 \
+ register long r1 __asm__("r1") = arg2;
+#define REGISTER_DECL_3 \
+ REGISTER_DECL_2 \
+ register long r2 __asm__("r2") = arg3;
+#define REGISTER_DECL_4 \
+ REGISTER_DECL_3 \
+ register long r3 __asm__("r3") = arg4;
+#define REGISTER_DECL_5 \
+ REGISTER_DECL_4 \
+ register long r4 __asm__("r4") = arg5;
+#define REGISTER_DECL_6 \
+ REGISTER_DECL_5 \
+ register long r5 __asm__("r5") = arg6;
+
+#define REGISTER_CONSTRAINT_0 "r"(r6)
+#define REGISTER_CONSTRAINT_1 REGISTER_CONSTRAINT_0, "r"(r0)
+#define REGISTER_CONSTRAINT_2 REGISTER_CONSTRAINT_1, "r"(r1)
+#define REGISTER_CONSTRAINT_3 REGISTER_CONSTRAINT_2, "r"(r2)
+#define REGISTER_CONSTRAINT_4 REGISTER_CONSTRAINT_3, "r"(r3)
+#define REGISTER_CONSTRAINT_5 REGISTER_CONSTRAINT_4, "r"(r4)
+#define REGISTER_CONSTRAINT_6 REGISTER_CONSTRAINT_5, "r"(r5)
+
+#define SYSCALL_INSTR(input_constraint) \
+ LIBC_INLINE_ASM("trap0(#1)" : "=r"(r0) : input_constraint : "memory", "cc")
+
+namespace LIBC_NAMESPACE {
+
+LIBC_INLINE long syscall_impl(long number) {
+ REGISTER_DECL_0;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_0);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1) {
+ REGISTER_DECL_1;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_1);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1, long arg2) {
+ REGISTER_DECL_2;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_2);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3) {
+ REGISTER_DECL_3;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_3);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
+ long arg4) {
+ REGISTER_DECL_4;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_4);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
+ long arg4, long arg5) {
+ REGISTER_DECL_5;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_5);
+ return r0;
+}
+
+LIBC_INLINE long syscall_impl(long number, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6) {
+ REGISTER_DECL_6;
+ SYSCALL_INSTR(REGISTER_CONSTRAINT_6);
+ return r0;
+}
+
+} // namespace LIBC_NAMESPACE
+
+#undef REGISTER_DECL_0
+#undef REGISTER_DECL_1
+#undef REGISTER_DECL_2
+#undef REGISTER_DECL_3
+#undef REGISTER_DECL_4
+#undef REGISTER_DECL_5
+#undef REGISTER_DECL_6
+
+#undef REGISTER_CONSTRAINT_0
+#undef REGISTER_CONSTRAINT_1
+#undef REGISTER_CONSTRAINT_2
+#undef REGISTER_CONSTRAINT_3
+#undef REGISTER_CONSTRAINT_4
+#undef REGISTER_CONSTRAINT_5
+#undef REGISTER_CONSTRAINT_6
+
+#endif // LLVM_LIBC_SRC_SUPPORT_OSUTIL_LINUX_HEXAGON_SYSCALL_H
diff --git a/libc/src/__support/OSUtil/linux/syscall.h b/libc/src/__support/OSUtil/linux/syscall.h
index 2be3cefa906af1..e03b9144ad7004 100644
--- a/libc/src/__support/OSUtil/linux/syscall.h
+++ b/libc/src/__support/OSUtil/linux/syscall.h
@@ -21,6 +21,8 @@
#include "arm/syscall.h"
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
#include "riscv/syscall.h"
+#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+#include "hexagon/syscall.h"
#endif
namespace LIBC_NAMESPACE {
diff --git a/libc/src/__support/RPC/rpc_util.h b/libc/src/__support/RPC/rpc_util.h
index 04620b0487f4ad..9c6b38daed5a30 100644
--- a/libc/src/__support/RPC/rpc_util.h
+++ b/libc/src/__support/RPC/rpc_util.h
@@ -27,6 +27,8 @@ LIBC_INLINE void sleep_briefly() {
__builtin_amdgcn_s_sleep(2);
#elif defined(LIBC_TARGET_ARCH_IS_X86)
__builtin_ia32_pause();
+#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+ LIBC_INLINE_ASM("pause(#255)");
#else
// Simply do nothing if sleeping isn't supported on this platform.
#endif
diff --git a/libc/src/__support/macros/properties/architectures.h b/libc/src/__support/macros/properties/architectures.h
index c88956ff41148e..7284ed71d637fd 100644
--- a/libc/src/__support/macros/properties/architectures.h
+++ b/libc/src/__support/macros/properties/architectures.h
@@ -61,4 +61,8 @@
#define LIBC_TARGET_ARCH_IS_ANY_RISCV
#endif
+#if defined(__hexagon__)
+#define LIBC_TARGET_ARCH_IS_HEXAGON
+#endif
+
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_ARCHITECTURES_H
diff --git a/libc/src/__support/macros/properties/float.h b/libc/src/__support/macros/properties/float.h
index c40ca6120e4753..8585dcdefaaa02 100644
--- a/libc/src/__support/macros/properties/float.h
+++ b/libc/src/__support/macros/properties/float.h
@@ -18,11 +18,12 @@
// https://developer.arm.com/documentation/dui0491/i/C-and-C---Implementation-Details/Basic-data-types
// https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
// https://docs.amd.com/bundle/HIP-Programming-Guide-v5.1/page/Programming_with_HIP.html
+// https://lists.llvm.org/pipermail/llvm-dev/attachments/20190916/21516a52/attachment-0001.pdf
#if defined(LIBC_TARGET_OS_IS_WINDOWS) || \
(defined(LIBC_TARGET_OS_IS_MACOS) && \
defined(LIBC_TARGET_ARCH_IS_AARCH64)) || \
defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_NVPTX) || \
- defined(LIBC_TARGET_ARCH_IS_AMDGPU)
+ defined(LIBC_TARGET_ARCH_IS_AMDGPU) || defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#define LONG_DOUBLE_IS_DOUBLE
#endif
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 5c84266ee5d0ed..025f2f663c1bdf 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -61,6 +61,8 @@ static constexpr unsigned CLONE_SYSCALL_FLAGS =
#define CLONE_RESULT_REGISTER "t0"
#elif defined(LIBC_TARGET_ARCH_IS_X86_64)
#define CLONE_RESULT_REGISTER "rax"
+#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+#define CLONE_RESULT_REGISTER "r0"
#else
#error "CLONE_RESULT_REGISTER not defined for your target architecture"
#endif
@@ -297,7 +299,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack,
// Also, we want the result of the syscall to be in a register as the child
// thread gets a completely different stack after it is created. The stack
// variables from this function will not be availalbe to the child thread.
-#if defined(LIBC_TARGET_ARCH_IS_X86_64)
+#if defined(LIBC_TARGET_ARCH_IS_X86_64) || defined(LIBC_TARGET_ARCH_IS_HEXAGON)
long register clone_result asm(CLONE_RESULT_REGISTER);
clone_result = LIBC_NAMESPACE::syscall_impl<long>(
SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack,
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index acfe33879f8783..42132941be4f35 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -43,6 +43,8 @@ union ThreadReturnValue {
defined(LIBC_TARGET_ARCH_IS_X86_64) || \
defined(LIBC_TARGET_ARCH_IS_ANY_RISCV))
constexpr unsigned int STACK_ALIGNMENT = 16;
+#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+constexpr unsigned int STACK_ALIGNMENT = 8;
#endif
// TODO: Provide stack alignment requirements for other architectures.
diff --git a/libc/src/setjmp/hexagon/CMakeLists.txt b/libc/src/setjmp/hexagon/CMakeLists.txt
new file mode 100644
index 00000000000000..8c6c8e204abd77
--- /dev/null
+++ b/libc/src/setjmp/hexagon/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_entrypoint_object(
+ setjmp
+ SRCS
+ setjmp.cpp
+ HDRS
+ ../setjmp_impl.h
+ DEPENDS
+ libc.include.setjmp
+ COMPILE_OPTIONS
+ -O3
+ -fomit-frame-pointer
+)
+
+add_entrypoint_object(
+ longjmp
+ SRCS
+ longjmp.cpp
+ HDRS
+ ../longjmp.h
+ DEPENDS
+ libc.include.setjmp
+ COMPILE_OPTIONS
+ -O3
+ -fomit-frame-pointer
+)
diff --git a/libc/src/setjmp/hexagon/longjmp.cpp b/libc/src/setjmp/hexagon/longjmp.cpp
new file mode 100644
index 00000000000000..ee334553155103
--- /dev/null
+++ b/libc/src/setjmp/hexagon/longjmp.cpp
@@ -0,0 +1,37 @@
+//===-- Hexagon implementation of longjmp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/setjmp/longjmp.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/properties/architectures.h"
+
+#include <setjmp.h>
+
+#if !defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+#error "Invalid file include"
+#endif
+
+#define LOAD(reg, val) LIBC_INLINE_ASM(#reg " = memd(%0)\n\t" : : "r"(&val) :)
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(void, longjmp, (__jmp_buf * buf, int val)) {
+ LOAD(r17:16, buf->__regs[0]);
+ LOAD(r19:18, buf->__regs[2]);
+ LOAD(r21:20, buf->__regs[4]);
+ LOAD(r23:22, buf->__regs[6]);
+ LOAD(r25:24, buf->__regs[8]);
+ LOAD(r27:26, buf->__regs[10]);
+ LOAD(r29:28, buf->__regs[12]);
+ LOAD(r31:30, buf->__regs[14]);
+
+ val = val == 0 ? 1 : val;
+ LIBC_INLINE_ASM("r0 = %0\n\t" : : "r"(val) :);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/setjmp/hexagon/setjmp.cpp b/libc/src/setjmp/hexagon/setjmp.cpp
new file mode 100644
index 00000000000000..5c936f29f7ed5d
--- /dev/null
+++ b/libc/src/setjmp/hexagon/setjmp.cpp
@@ -0,0 +1,36 @@
+//===-- Hexagon implementation of setjmp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "src/setjmp/setjmp_impl.h"
+
+#include <setjmp.h>
+
+#if !defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+#error "Invalid file include"
+#endif
+
+#define STORE(reg, val) \
+ LIBC_INLINE_ASM("memd(%0) = " #reg "\n\t" : : "r"(&val) :)
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, setjmp, (__jmp_buf * buf)) {
+ STORE(r17:16, buf->__regs[0]);
+ STORE(r19:18, buf->__regs[2]);
+ STORE(r21:20, buf->__regs[4]);
+ STORE(r23:22, buf->__regs[6]);
+ STORE(r25:24, buf->__regs[8]);
+ STORE(r27:26, buf->__regs[10]);
+ STORE(r29:28, buf->__regs[12]);
+ STORE(r31:30, buf->__regs[14]);
+
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/string/memory_utils/inline_bcmp.h b/libc/src/string/memory_utils/inline_bcmp.h
index b1c981d859e022..49479ba17a6546 100644
--- a/libc/src/string/memory_utils/inline_bcmp.h
+++ b/libc/src/string/memory_utils/inline_bcmp.h
@@ -23,7 +23,8 @@
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
#include "src/string/memory_utils/riscv/inline_bcmp.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_BCMP inline_bcmp_riscv
-#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU)
+#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU) || \
+ defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#include "src/string/memory_utils/generic/byte_per_byte.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_BCMP inline_bcmp_byte_per_byte
#else
diff --git a/libc/src/string/memory_utils/inline_memcmp.h b/libc/src/string/memory_utils/inline_memcmp.h
index d88d43691daee8..e3421fb9b61dbc 100644
--- a/libc/src/string/memory_utils/inline_memcmp.h
+++ b/libc/src/string/memory_utils/inline_memcmp.h
@@ -24,7 +24,8 @@
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
#include "src/string/memory_utils/riscv/inline_memcmp.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCMP inline_memcmp_riscv
-#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU)
+#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_GPU) || \
+ defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#include "src/string/memory_utils/generic/byte_per_byte.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCMP inline_memcmp_byte_per_byte
#else
diff --git a/libc/src/string/memory_utils/inline_memcpy.h b/libc/src/string/memory_utils/inline_memcpy.h
index a92bf4ddf881d5..75710d7c360455 100644
--- a/libc/src/string/memory_utils/inline_memcpy.h
+++ b/libc/src/string/memory_utils/inline_memcpy.h
@@ -28,7 +28,7 @@
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
#include "src/string/memory_utils/riscv/inline_memcpy.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_riscv
-#elif defined(LIBC_TARGET_ARCH_IS_ARM)
+#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#include "src/string/memory_utils/generic/byte_per_byte.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_byte_per_byte
#elif defined(LIBC_TARGET_ARCH_IS_GPU)
diff --git a/libc/src/string/memory_utils/inline_memmove.h b/libc/src/string/memory_utils/inline_memmove.h
index 30c2c3ddbf1bb7..753ffc09c77736 100644
--- a/libc/src/string/memory_utils/inline_memmove.h
+++ b/libc/src/string/memory_utils/inline_memmove.h
@@ -27,7 +27,7 @@
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \
inline_memmove_no_small_size
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_FOLLOW_UP inline_memmove_riscv
-#elif defined(LIBC_TARGET_ARCH_IS_ARM)
+#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#include "src/string/memory_utils/generic/byte_per_byte.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \
inline_memmove_no_small_size
diff --git a/libc/src/string/memory_utils/inline_memset.h b/libc/src/string/memory_utils/inline_memset.h
index 1c07c1ca4bffc0..4d7b01479c421a 100644
--- a/libc/src/string/memory_utils/inline_memset.h
+++ b/libc/src/string/memory_utils/inline_memset.h
@@ -24,7 +24,7 @@
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
#include "src/string/memory_utils/riscv/inline_memset.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_riscv
-#elif defined(LIBC_TARGET_ARCH_IS_ARM)
+#elif defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_HEXAGON)
#include "src/string/memory_utils/generic/byte_per_byte.h"
#define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_byte_per_byte
#elif defined(LIBC_TARGET_ARCH_IS_GPU)
diff --git a/libc/startup/linux/hexagon/CMakeLists.txt b/libc/startup/linux/hexagon/CMakeLists.txt
new file mode 100644
index 00000000000000..b47db8eb5d23f3
--- /dev/null
+++ b/libc/startup/linux/hexagon/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_startup_object(
+ crt1
+ SRC
+ start.cpp
+ DEPENDS
+ libc.config.linux.app_h
+ libc.include.sys_mman
+ libc.include.sys_syscall
+ libc.src.__support.threads.thread
+ libc.src.__support.OSUtil.osutil
+ libc.src.stdlib.exit
+ libc.src.stdlib.atexit
+ libc.src.string.memory_utils.inline_memcpy
+ libc.src.unistd.environ
+ COMPILE_OPTIONS
+ -fno-omit-frame-pointer
+ -ffreestanding # To avoid compiler warnings about calling the main function.
+)
diff --git a/libc/startup/linux/hexagon/start.cpp b/libc/startup/linux/hexagon/start.cpp
new file mode 100644
index 00000000000000..14c6164b860568
--- /dev/null
+++ b/libc/startup/linux/hexagon/start.cpp
@@ -0,0 +1,235 @@
+//===-- Implementation of crt for hexagon
+//----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "config/linux/app.h"
+#include "src/__support/OSUtil/syscall.h"
+#include "src/__support/threads/thread.h"
+#include "src/stdlib/atexit.h"
+#include "src/stdlib/exit.h"
+#include "src/string/memory_utils/inline_memcpy.h"
+
+#include <linux/auxvec.h>
+#include <linux/elf.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+extern "C" int main(int, char **, char **);
+
+namespace LIBC_NAMESPACE {
+
+#ifdef SYS_mmap2
+static constexpr long mmapSyscallNumber = SYS_mmap2;
+#elif SYS_mmap
+static constexpr long mmapSyscallNumber = SYS_mmap;
+#else
+#error "mmap and mmap2 syscalls not available."
+#endif
+
+AppProperties app;
+
+static ThreadAttributes main_thread_attrib;
+
+// TODO: The function is hexagon specific. Move it to config/linux/app.h
+// and generalize it. Also, dynamic loading is not handled currently.
+void init_tls(TLSDescriptor &tls_descriptor) {
+ if (app.tls.size == 0) {
+ tls_descriptor.size = 0;
+ tls_descriptor.tp = 0;
+ return;
+ }
+
+ // We will assume the alignment is always a power of two.
+ uintptr_t tlsSize = app.tls.size & -app.tls.align;
+ if (tlsSize != app.tls.size)
+ tlsSize += app.tls.align;
+
+ // Per the hexagon ABI, the entry pointed to by the thread pointer is the
+ // address of the TLS block. So, we add more size to accomodate this address
+ // entry.
+ uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t);
+
+ // We cannot call the mmap function here as the functions set errno on
+ // failure. Since errno is implemented via a thread local variable, we cannot
+ // use errno before TLS is setup.
+ long mmapRetVal = LIBC_NAMESPACE::syscall_impl<long>(
+ mmapSyscallNumber, nullptr, tlsSizeWithAddr, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ // We cannot check the return value with MAP_FAILED as that is the return
+ // of the mmap function and not the mmap syscall.
+ if (mmapRetVal < 0 && static_cast<uintptr_t>(mmapRetVal) > -app.pageSize)
+ LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 1);
+ uintptr_t *tlsAddr = reinterpret_cast<uintptr_t *>(mmapRetVal);
+
+ // hexagon TLS faces down from the thread pointer with the first entry
+ // pointing to the address of the first real TLS byte.
+ uintptr_t endPtr = reinterpret_cast<uintptr_t>(tlsAddr) + tlsSize;
+ *reinterpret_cast<uintptr_t *>(endPtr) = endPtr;
+
+ LIBC_NAMESPACE::inline_memcpy(reinterpret_cast<char *>(tlsAddr),
+ reinterpret_cast<const char *>(app.tls.address),
+ app.tls.init_size);
+
+ tls_descriptor = {tlsSizeWithAddr, uintptr_t(tlsAddr), endPtr};
+ return;
+}
+
+void cleanup_tls(uintptr_t addr, uintptr_t size) {
+ if (size == 0)
+ return;
+ LIBC_NAMESPACE::syscall_impl<long>(SYS_munmap, addr, size);
+}
+
+// Sets the thread pointer to |val|. Returns true on success, false on failure.
+static void set_thread_ptr(uintptr_t val) {
+ LIBC_INLINE_ASM("ugp = %0" : "=r"(val));
+}
+
+using InitCallback = void(int, char **, char **);
+using FiniCallback = void(void);
+
+extern "C" {
+// These arrays are present in the .init_array and .fini_array sections.
+// The symbols are inserted by linker when it sees references to them.
+extern uintptr_t __preinit_array_start[];
+extern uintptr_t __preinit_array_end[];
+extern uintptr_t __init_array_start[];
+extern uintptr_t __init_array_end[];
+extern uintptr_t __fini_array_start[];
+extern uintptr_t __fini_array_end[];
+}
+
+static void call_init_array_callbacks(int argc, char **argv, char **env) {
+ size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
+ for (size_t i = 0; i < preinit_array_size; ++i)
+ reinterpret_cast<InitCallback *>(__preinit_array_start[i])(argc, argv, env);
+ size_t init_array_size = __init_array_end - __init_array_start;
+ for (size_t i = 0; i < init_array_size; ++i)
+ reinterpret_cast<InitCallback *>(__init_array_start[i])(argc, argv, env);
+}
+
+static void call_fini_array_callbacks() {
+ size_t fini_array_size = __fini_array_end - __fini_array_start;
+ for (size_t i = fini_array_size; i > 0; --i)
+ reinterpret_cast<FiniCallback *>(__fini_array_start[i - 1])();
+}
+
+} // namespace LIBC_NAMESPACE
+
+using LIBC_NAMESPACE::app;
+
+// TODO: Would be nice to use the aux entry structure from elf.h when available.
+struct AuxEntry {
+ uint64_t type;
+ uint64_t value;
+};
+
+extern "C" void _start() {
+#if 0
+ // This TU is compiled with -fno-omit-frame-pointer. Hence, the previous value
+ // of the base pointer is pushed on to the stack. So, we step over it (the
+ // "+ 1" below) to get to the args.
+ app.args = reinterpret_cast<LIBC_NAMESPACE::Args *>(
+ reinterpret_cast<uintptr_t *>(__builtin_frame_address(0)) + 1);
+
+ // The hexagon ABI requires that the stack pointer is aligned to a 8-byte
+ // boundary. We align it here but we cannot use any local variables created
+ // before the following alignment. Best would be to not create any local
+ // variables before the alignment. Also, note that we are aligning the stack
+ // downwards as the hexagon stack grows downwards. This ensures that we don't
+ // tread on argc, argv etc.
+ // NOTE: Compiler attributes for alignment do not help here as the stack
+ // pointer on entry to this _start function is controlled by the OS. In fact,
+ // compilers can generate code assuming the alignment as required by the ABI.
+ // If the stack pointers as setup by the OS are already aligned, then the
+ // following code is a NOP.
+ __asm__ __volatile__("nop\n\t");
+
+ auto tid = LIBC_NAMESPACE::syscall_impl<long>(SYS_gettid);
+ if (tid <= 0)
+ LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 1);
+ LIBC_NAMESPACE::main_thread_attrib.tid = static_cast<int>(tid);
+
+ // After the argv array, is a 8-byte long NULL value before the array of env
+ // values. The end of the env values is marked by another 8-byte long NULL
+ // value. We step over it (the "+ 1" below) to get to the env values.
+ uint32_t *env_ptr = app.args->argv + app.args->argc + 1;
+ uint32_t *env_end_marker = env_ptr;
+ app.envPtr = env_ptr;
+ while (*env_end_marker)
+ ++env_end_marker;
+
+ // Initialize the POSIX global declared in unistd.h
+ environ = reinterpret_cast<char **>(env_ptr);
+
+ // After the env array, is the aux-vector. The end of the aux-vector is
+ // denoted by an AT_NULL entry.
+ Elf64_Phdr *programHdrTable = nullptr;
+ uintptr_t programHdrCount;
+ for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
+ aux_entry->type != AT_NULL; ++aux_entry) {
+ switch (aux_entry->type) {
+ case AT_PHDR:
+ programHdrTable = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
+ break;
+ case AT_PHNUM:
+ programHdrCount = aux_entry->value;
+ break;
+ case AT_PAGESZ:
+ app.pageSize = aux_entry->value;
+ break;
+ default:
+ break; // TODO: Read other useful entries from the aux vector.
+ }
+ }
+
+ app.tls.size = 0;
+ for (uintptr_t i = 0; i < programHdrCount; ++i) {
+ Elf64_Phdr *phdr = programHdrTable + i;
+ if (phdr->p_type != PT_TLS)
+ continue;
+ // TODO: p_vaddr value has to be adjusted for static-pie executables.
+ app.tls.address = phdr->p_vaddr;
+ app.tls.size = phdr->p_memsz;
+ app.tls.init_size = phdr->p_filesz;
+ app.tls.align = phdr->p_align;
+ }
+
+ LIBC_NAMESPACE::TLSDescriptor tls;
+ LIBC_NAMESPACE::init_tls(tls);
+ if (tls.size != 0)
+ LIBC_NAMESPACE::set_thread_ptr(tls.tp);
+
+ LIBC_NAMESPACE::self.attrib = &LIBC_NAMESPACE::main_thread_attrib;
+ LIBC_NAMESPACE::main_thread_attrib.atexit_callback_mgr =
+ LIBC_NAMESPACE::internal::get_thread_atexit_callback_mgr();
+
+ // We want the fini array callbacks to be run after other atexit
+ // callbacks are run. So, we register them before running the init
+ // array callbacks as they can potentially register their own atexit
+ // callbacks.
+ LIBC_NAMESPACE::atexit(&LIBC_NAMESPACE::call_fini_array_callbacks);
+
+ LIBC_NAMESPACE::call_init_array_callbacks(
+ static_cast<int>(app.args->argc),
+ reinterpret_cast<char **>(app.args->argv),
+ reinterpret_cast<char **>(env_ptr));
+
+ int retval = main(static_cast<int>(app.args->argc),
+ reinterpret_cast<char **>(app.args->argv),
+ reinterpret_cast<char **>(env_ptr));
+
+ // TODO: TLS cleanup should be done after all other atexit callbacks
+ // are run. So, register a cleanup callback for it with atexit before
+ // everything else.
+ LIBC_NAMESPACE::cleanup_tls(tls.addr, tls.size);
+ LIBC_NAMESPACE::exit(retval);
+#endif
+}
>From 0f5b4b41fb43a94a5e4363cee5671d38eff16c96 Mon Sep 17 00:00:00 2001
From: Brian Cain <bcain at quicinc.com>
Date: Fri, 20 Oct 2023 19:09:41 -0700
Subject: [PATCH 2/4] hacks to make tests build/pass - DO NOT MERGE
These are all useful for making the build / tests pass but need some official
resolution.
* explicit CMAKE_CROSSCOMPILING_EMULATOR - normally this shouldn't be required
* missing `wint_t` typedef. known/outstanding issue https://github.com/llvm/llvm-project/issues/63510 ?
* workaround for missing `-nolibc` in the toolchain
* adjust timeouts for LibcDeathTestExecutors - test under emulation takes longer
---
libc/CMakeLists.txt | 5 +++++
libc/cmake/modules/LLVMLibCTestRules.cmake | 9 ++++++---
libc/include/llvm-libc-types/wint_t.h | 4 ++++
libc/test/UnitTest/LibcDeathTestExecutors.cpp | 8 ++++----
4 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 9c82db754b5f73..b3107b95d396fc 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -269,6 +269,11 @@ if(LLVM_LIBC_ENABLE_LINTING)
endif()
endif()
+if(LIBC_TARGET_ARCHITECTURE STREQUAL "hexagon")
+ add_compile_options(-mlong-calls)
+endif()
+
+
option(LLVM_LIBC_INCLUDE_SCUDO "Include the SCUDO standalone as the allocator for LLVM libc" OFF)
if(LLVM_LIBC_INCLUDE_SCUDO)
if (NOT ("compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS OR "compiler-rt" IN_LIST LLVM_ENABLE_RUNTIMES))
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index 6cae0859149d54..45647106d19c4b 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -212,7 +212,7 @@ function(create_libc_unittest fq_target_name)
if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD)
add_custom_target(
${fq_target_name}
- COMMAND ${fq_build_target_name}
+ COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} ${fq_build_target_name}
COMMENT "Running unit test ${fq_target_name}"
)
endif()
@@ -538,9 +538,12 @@ function(add_integration_test test_name)
if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static)
+ elseif(LIBC_TARGET_ARCHITECTURE_IS_HEXAGON)
+ target_link_options(${fq_build_target_name} PRIVATE -nostdlib -static -lclang_rt.builtins-hexagon)
else()
target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib++ -static)
endif()
+
target_link_libraries(
${fq_build_target_name}
# The NVIDIA 'nvlink' linker does not currently support static libraries.
@@ -571,7 +574,7 @@ function(add_integration_test test_name)
$<TARGET_FILE:${fq_build_target_name}> ${INTEGRATION_TEST_ARGS})
add_custom_target(
${fq_target_name}
- COMMAND ${test_cmd}
+ COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} ${test_cmd}
COMMAND_EXPAND_LISTS
COMMENT "Running integration test ${fq_target_name}"
)
@@ -737,7 +740,7 @@ function(add_libc_hermetic_test test_name)
$<TARGET_FILE:${fq_build_target_name}> ${HERMETIC_TEST_ARGS})
add_custom_target(
${fq_target_name}
- COMMAND ${test_cmd}
+ COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} ${test_cmd}
COMMAND_EXPAND_LISTS
COMMENT "Running hermetic test ${fq_target_name}"
${LIBC_HERMETIC_TEST_JOB_POOL}
diff --git a/libc/include/llvm-libc-types/wint_t.h b/libc/include/llvm-libc-types/wint_t.h
index cf6ccd7e1ae765..abfa6103941561 100644
--- a/libc/include/llvm-libc-types/wint_t.h
+++ b/libc/include/llvm-libc-types/wint_t.h
@@ -12,6 +12,10 @@
// Since __need_wint_t is defined, we get the definition of wint_t from the
// standalone C header stddef.h. Also, because __need_wint_t is defined,
// including stddef.h will pull only the type wint_t and nothing else.
+#if defined(__hexagon__)
+typedef int wint_t;
+#endif
+
#define __need_wint_t
#include <stddef.h>
#undef __need_wint_t
diff --git a/libc/test/UnitTest/LibcDeathTestExecutors.cpp b/libc/test/UnitTest/LibcDeathTestExecutors.cpp
index e891c4e3c0b586..4deff4614987eb 100644
--- a/libc/test/UnitTest/LibcDeathTestExecutors.cpp
+++ b/libc/test/UnitTest/LibcDeathTestExecutors.cpp
@@ -19,7 +19,7 @@ namespace testing {
bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,
const char *LHSStr, const char *RHSStr,
internal::Location Loc) {
- testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
+ testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 5000);
if (const char *error = Result.get_error()) {
Ctx->markFail();
@@ -31,7 +31,7 @@ bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,
if (Result.timed_out()) {
Ctx->markFail();
tlog << Loc;
- tlog << "Process timed out after " << 500 << " milliseconds.\n";
+ tlog << "Process timed out after " << 5000 << " milliseconds.\n";
return false;
}
@@ -62,7 +62,7 @@ bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,
bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
const char *LHSStr, const char *RHSStr,
internal::Location Loc) {
- testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 500);
+ testutils::ProcessStatus Result = testutils::invoke_in_subprocess(Func, 5000);
if (const char *error = Result.get_error()) {
Ctx->markFail();
@@ -74,7 +74,7 @@ bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
if (Result.timed_out()) {
Ctx->markFail();
tlog << Loc;
- tlog << "Process timed out after " << 500 << " milliseconds.\n";
+ tlog << "Process timed out after " << 5000 << " milliseconds.\n";
return false;
}
>From 5566d88cadfb8317ec68798a355e63383b21cc73 Mon Sep 17 00:00:00 2001
From: Brian Cain <bcain at quicinc.com>
Date: Fri, 24 Nov 2023 19:06:22 -0800
Subject: [PATCH 3/4] Fix "undeclared identifier" error
This change is required to fix this error:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/stdio/printf_core/converter.cpp:9:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/stdio/printf_core/converter.h:12:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/stdio/printf_core/core_structs.h:13:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/__support/FPUtil/FPBits.h:17:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/__support/FPUtil/FloatProperties.h:12:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/__support/UInt128.h:12:
In file included from /local/mnt/workspace/upstream/llvm-project/libc/src/__support/UInt.h:17:
/local/mnt/workspace/upstream/llvm-project/libc/src/__support/integer_utils.h:51:13: error: use of undeclared identifier 'add_with_carry'
51 | auto r1 = add_with_carry(prod.lo, lo_hi.lo << 32, uint64_t(0));
| ^
/local/mnt/workspace/upstream/llvm-project/libc/src/__support/integer_utils.h:55:13: error: use of undeclared identifier 'add_with_carry'
55 | auto r2 = add_with_carry(prod.lo, hi_lo.lo << 32, uint64_t(0));
| ^
---
libc/src/__support/integer_utils.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/src/__support/integer_utils.h b/libc/src/__support/integer_utils.h
index 433e99227bcfd4..661318f03bfd31 100644
--- a/libc/src/__support/integer_utils.h
+++ b/libc/src/__support/integer_utils.h
@@ -13,6 +13,7 @@
#include "src/__support/common.h"
#include "bit.h"
+#include "math_extras.h"
#include "number_pair.h"
#include <stdint.h>
>From 1343ea126775d77ad97223b2b86aae0dab6c8ac8 Mon Sep 17 00:00:00 2001
From: Brian Cain <bcain at quicinc.com>
Date: Fri, 22 Sep 2023 10:19:56 -0700
Subject: [PATCH 4/4] fixes for startup
---
libc/startup/linux/hexagon/start.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/libc/startup/linux/hexagon/start.cpp b/libc/startup/linux/hexagon/start.cpp
index 14c6164b860568..b913dd404d7baf 100644
--- a/libc/startup/linux/hexagon/start.cpp
+++ b/libc/startup/linux/hexagon/start.cpp
@@ -127,12 +127,12 @@ using LIBC_NAMESPACE::app;
// TODO: Would be nice to use the aux entry structure from elf.h when available.
struct AuxEntry {
- uint64_t type;
- uint64_t value;
+ uint32_t type;
+ uint32_t value;
};
extern "C" void _start() {
-#if 0
+#if 1
// This TU is compiled with -fno-omit-frame-pointer. Hence, the previous value
// of the base pointer is pushed on to the stack. So, we step over it (the
// "+ 1" below) to get to the args.
@@ -150,7 +150,7 @@ extern "C" void _start() {
// compilers can generate code assuming the alignment as required by the ABI.
// If the stack pointers as setup by the OS are already aligned, then the
// following code is a NOP.
- __asm__ __volatile__("nop\n\t");
+ LIBC_INLINE_ASM("r29 = and(r29, #0xfffffff8)\n\t" :::);
auto tid = LIBC_NAMESPACE::syscall_impl<long>(SYS_gettid);
if (tid <= 0)
@@ -171,13 +171,13 @@ extern "C" void _start() {
// After the env array, is the aux-vector. The end of the aux-vector is
// denoted by an AT_NULL entry.
- Elf64_Phdr *programHdrTable = nullptr;
+ Elf32_Phdr *programHdrTable = nullptr;
uintptr_t programHdrCount;
for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
aux_entry->type != AT_NULL; ++aux_entry) {
switch (aux_entry->type) {
case AT_PHDR:
- programHdrTable = reinterpret_cast<Elf64_Phdr *>(aux_entry->value);
+ programHdrTable = reinterpret_cast<Elf32_Phdr *>(aux_entry->value);
break;
case AT_PHNUM:
programHdrCount = aux_entry->value;
@@ -192,7 +192,7 @@ extern "C" void _start() {
app.tls.size = 0;
for (uintptr_t i = 0; i < programHdrCount; ++i) {
- Elf64_Phdr *phdr = programHdrTable + i;
+ Elf32_Phdr *phdr = programHdrTable + i;
if (phdr->p_type != PT_TLS)
continue;
// TODO: p_vaddr value has to be adjusted for static-pie executables.
More information about the libc-commits
mailing list