[libc-commits] [libc] [libc] Add bare-metal Hexagon port (PR #217528)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 28 07:59:11 PDT 2026
https://github.com/quic-k updated https://github.com/llvm/llvm-project/pull/217528
>From 89ea5c9cf52065c67e0d14eb431f3c785eb82bae Mon Sep 17 00:00:00 2001
From: Kushal Pal <kushpal at qti.qualcomm.com>
Date: Mon, 17 Aug 2026 19:46:48 +0530
Subject: [PATCH] [libc] Add bare-metal Hexagon port
Add support for llvm-libc on Hexagon bare-metal targets.
Recognize the hexagon architecture in CMake.
Add the Hexagon bare-metal config: entrypoints.txt and headers.txt, reusing
the common bare-metal config.json.
Add Hexagon startup code (crt1) with semihosting trap handling.
Add a Hexagon FEnvImpl and select it in FEnvImpl.h; define fenv_t for Hexagon.
Add Hexagon setjmp/longjmp, saving the callee-saved registers r16-r27 as
register pairs along with sp, fp and lr, and define __jmp_buf accordingly.
Signed-off-by: Kushal Pal <kushpal at qti.qualcomm.com>
---
.../cmake/modules/LLVMLibCArchitectures.cmake | 4 +
libc/config/baremetal/hexagon/entrypoints.txt | 998 ++++++++++++++++++
libc/config/baremetal/hexagon/headers.txt | 32 +
libc/include/llvm-libc-types/__jmp_buf.h | 6 +
libc/include/llvm-libc-types/fenv_t.h | 2 +
libc/src/__support/FPUtil/FEnvImpl.h | 2 +
libc/src/__support/FPUtil/hexagon/FEnvImpl.h | 210 ++++
.../macros/properties/architectures.h | 4 +
libc/src/__support/memory_size.h | 7 +-
libc/src/setjmp/hexagon/CMakeLists.txt | 19 +
libc/src/setjmp/hexagon/longjmp.cpp | 35 +
libc/src/setjmp/hexagon/setjmp.cpp | 36 +
libc/startup/baremetal/hexagon/CMakeLists.txt | 12 +
libc/startup/baremetal/hexagon/start.cpp | 95 ++
libc/test/UnitTest/CMakeLists.txt | 24 +-
.../UnitTest/HexagonBaremetalTestUtils.cpp | 119 +++
libc/test/UnitTest/LibcTest.cpp | 8 +-
libc/test/UnitTest/LibcTest.h | 2 +
libc/test/UnitTest/llvm-libc-baremetal.ld | 3 +
libc/test/src/math/smoke/exp10m1f_test.cpp | 11 +-
20 files changed, 1614 insertions(+), 15 deletions(-)
create mode 100644 libc/config/baremetal/hexagon/entrypoints.txt
create mode 100644 libc/config/baremetal/hexagon/headers.txt
create mode 100644 libc/src/__support/FPUtil/hexagon/FEnvImpl.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/baremetal/hexagon/CMakeLists.txt
create mode 100644 libc/startup/baremetal/hexagon/start.cpp
create mode 100644 libc/test/UnitTest/HexagonBaremetalTestUtils.cpp
diff --git a/libc/cmake/modules/LLVMLibCArchitectures.cmake b/libc/cmake/modules/LLVMLibCArchitectures.cmake
index 3149c16f9e2eb..327ddc5dfa5ce 100644
--- a/libc/cmake/modules/LLVMLibCArchitectures.cmake
+++ b/libc/cmake/modules/LLVMLibCArchitectures.cmake
@@ -53,6 +53,8 @@ function(get_arch_and_system_from_triple triple arch_var sys_var)
set(target_arch "nvptx")
elseif(target_arch MATCHES "^spirv")
set(target_arch "spirv")
+ elseif(target_arch MATCHES "^hexagon")
+ set(target_arch "hexagon")
else()
return()
endif()
@@ -190,6 +192,8 @@ elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "spirv")
set(LIBC_TARGET_ARCHITECTURE_IS_SPIRV TRUE)
elseif(LIBC_TARGET_ARCHITECTURE STREQUAL "power")
set(LIBC_TARGET_ARCHITECTURE_IS_POWERPC TRUE)
+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/baremetal/hexagon/entrypoints.txt b/libc/config/baremetal/hexagon/entrypoints.txt
new file mode 100644
index 0000000000000..c6244a2f4d728
--- /dev/null
+++ b/libc/config/baremetal/hexagon/entrypoints.txt
@@ -0,0 +1,998 @@
+set(TARGET_LIBC_ENTRYPOINTS
+ # assert.h entrypoints
+ libc.src.assert.__assert_fail
+
+ # compiler entrypoints (no corresponding header)
+ libc.src.compiler.__stack_chk_fail
+
+ # 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
+
+ # ctype.h entrypoints
+ libc.src.ctype.isalnum_l
+ libc.src.ctype.isalpha_l
+ libc.src.ctype.isblank_l
+ libc.src.ctype.iscntrl_l
+ libc.src.ctype.isdigit_l
+ libc.src.ctype.isgraph_l
+ libc.src.ctype.islower_l
+ libc.src.ctype.isprint_l
+ libc.src.ctype.ispunct_l
+ libc.src.ctype.isspace_l
+ libc.src.ctype.isupper_l
+ libc.src.ctype.isxdigit_l
+ libc.src.ctype.tolower_l
+ libc.src.ctype.toupper_l
+
+ # errno.h entrypoints
+ libc.src.errno.errno
+
+ # locale.h entrypoints
+ libc.src.locale.localeconv
+ libc.src.locale.duplocale
+ libc.src.locale.freelocale
+ libc.src.locale.localeconv
+ libc.src.locale.newlocale
+ libc.src.locale.setlocale
+ libc.src.locale.uselocale
+
+ # setjmp.h entrypoints
+ libc.src.setjmp.longjmp
+ libc.src.setjmp.setjmp
+
+ # string.h entrypoints
+ 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.memset_explicit
+ libc.src.string.stpcpy
+ libc.src.string.stpncpy
+ 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.strncat
+ libc.src.string.strncmp
+ libc.src.string.strncpy
+ libc.src.string.strndup
+ libc.src.string.strnlen
+ libc.src.string.strnlen_s
+ libc.src.string.strpbrk
+ libc.src.string.strrchr
+ libc.src.string.strsep
+ libc.src.string.strspn
+ libc.src.string.strstr
+ libc.src.string.strtok
+ libc.src.string.strtok_r
+ libc.src.string.strxfrm
+
+ # string.h entrypoints
+ libc.src.string.strcoll_l
+ libc.src.string.strxfrm_l
+
+ # strings.h entrypoints
+ libc.src.strings.bcmp
+ libc.src.strings.bcopy
+ libc.src.strings.bzero
+ libc.src.strings.ffs
+ libc.src.strings.ffsl
+ libc.src.strings.ffsll
+ libc.src.strings.index
+ libc.src.strings.rindex
+ libc.src.strings.strcasecmp
+ libc.src.strings.strncasecmp
+
+ # strings.h entrypoints
+ libc.src.strings.strcasecmp_l
+ libc.src.strings.strncasecmp_l
+
+ # inttypes.h entrypoints
+ libc.src.inttypes.imaxabs
+ libc.src.inttypes.imaxdiv
+ libc.src.inttypes.strtoimax
+ libc.src.inttypes.strtoumax
+
+ # stdio.h entrypoints
+ libc.src.stdio.asprintf
+ libc.src.stdio.feof
+ libc.src.stdio.ferror
+ libc.src.stdio.fgetc
+ libc.src.stdio.fgets
+ libc.src.stdio.fprintf
+ libc.src.stdio.fputc
+ libc.src.stdio.fputs
+ libc.src.stdio.fread
+ libc.src.stdio.fscanf
+ libc.src.stdio.fwrite
+ libc.src.stdio.getchar
+ libc.src.stdio.printf
+ libc.src.stdio.putc
+ libc.src.stdio.putchar
+ libc.src.stdio.puts
+ libc.src.stdio.remove
+ libc.src.stdio.scanf
+ libc.src.stdio.snprintf
+ libc.src.stdio.sprintf
+ libc.src.stdio.sscanf
+ libc.src.stdio.stderr
+ libc.src.stdio.stdin
+ libc.src.stdio.stdout
+ libc.src.stdio.vasprintf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vfscanf
+ libc.src.stdio.vprintf
+ libc.src.stdio.vscanf
+ libc.src.stdio.vsnprintf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vsscanf
+
+ # stdbit.h entrypoints
+ libc.src.stdbit.stdc_bit_ceil_uc
+ libc.src.stdbit.stdc_bit_ceil_ui
+ libc.src.stdbit.stdc_bit_ceil_ul
+ libc.src.stdbit.stdc_bit_ceil_ull
+ libc.src.stdbit.stdc_bit_ceil_us
+ libc.src.stdbit.stdc_bit_floor_uc
+ libc.src.stdbit.stdc_bit_floor_ui
+ libc.src.stdbit.stdc_bit_floor_ul
+ libc.src.stdbit.stdc_bit_floor_ull
+ libc.src.stdbit.stdc_bit_floor_us
+ libc.src.stdbit.stdc_bit_width_uc
+ libc.src.stdbit.stdc_bit_width_ui
+ libc.src.stdbit.stdc_bit_width_ul
+ libc.src.stdbit.stdc_bit_width_ull
+ libc.src.stdbit.stdc_bit_width_us
+ libc.src.stdbit.stdc_count_ones_uc
+ libc.src.stdbit.stdc_count_ones_ui
+ libc.src.stdbit.stdc_count_ones_ul
+ libc.src.stdbit.stdc_count_ones_ull
+ libc.src.stdbit.stdc_count_ones_us
+ libc.src.stdbit.stdc_count_zeros_uc
+ libc.src.stdbit.stdc_count_zeros_ui
+ libc.src.stdbit.stdc_count_zeros_ul
+ libc.src.stdbit.stdc_count_zeros_ull
+ libc.src.stdbit.stdc_count_zeros_us
+ libc.src.stdbit.stdc_first_leading_one_uc
+ libc.src.stdbit.stdc_first_leading_one_ui
+ libc.src.stdbit.stdc_first_leading_one_ul
+ libc.src.stdbit.stdc_first_leading_one_ull
+ libc.src.stdbit.stdc_first_leading_one_us
+ libc.src.stdbit.stdc_first_leading_zero_uc
+ libc.src.stdbit.stdc_first_leading_zero_ui
+ libc.src.stdbit.stdc_first_leading_zero_ul
+ libc.src.stdbit.stdc_first_leading_zero_ull
+ libc.src.stdbit.stdc_first_leading_zero_us
+ libc.src.stdbit.stdc_first_trailing_one_uc
+ libc.src.stdbit.stdc_first_trailing_one_ui
+ libc.src.stdbit.stdc_first_trailing_one_ul
+ libc.src.stdbit.stdc_first_trailing_one_ull
+ libc.src.stdbit.stdc_first_trailing_one_us
+ libc.src.stdbit.stdc_first_trailing_zero_uc
+ libc.src.stdbit.stdc_first_trailing_zero_ui
+ libc.src.stdbit.stdc_first_trailing_zero_ul
+ libc.src.stdbit.stdc_first_trailing_zero_ull
+ libc.src.stdbit.stdc_first_trailing_zero_us
+ libc.src.stdbit.stdc_has_single_bit_uc
+ libc.src.stdbit.stdc_has_single_bit_ui
+ libc.src.stdbit.stdc_has_single_bit_ul
+ libc.src.stdbit.stdc_has_single_bit_ull
+ libc.src.stdbit.stdc_has_single_bit_us
+ libc.src.stdbit.stdc_leading_ones_uc
+ libc.src.stdbit.stdc_leading_ones_ui
+ libc.src.stdbit.stdc_leading_ones_ul
+ libc.src.stdbit.stdc_leading_ones_ull
+ libc.src.stdbit.stdc_leading_ones_us
+ libc.src.stdbit.stdc_leading_zeros_uc
+ libc.src.stdbit.stdc_leading_zeros_ui
+ libc.src.stdbit.stdc_leading_zeros_ul
+ libc.src.stdbit.stdc_leading_zeros_ull
+ libc.src.stdbit.stdc_leading_zeros_us
+ libc.src.stdbit.stdc_trailing_ones_uc
+ libc.src.stdbit.stdc_trailing_ones_ui
+ libc.src.stdbit.stdc_trailing_ones_ul
+ libc.src.stdbit.stdc_trailing_ones_ull
+ libc.src.stdbit.stdc_trailing_ones_us
+ libc.src.stdbit.stdc_trailing_zeros_uc
+ libc.src.stdbit.stdc_trailing_zeros_ui
+ libc.src.stdbit.stdc_trailing_zeros_ul
+ libc.src.stdbit.stdc_trailing_zeros_ull
+ libc.src.stdbit.stdc_trailing_zeros_us
+
+ # stdlib.h entrypoints
+ libc.src.stdlib._Exit
+ libc.src.stdlib.a64l
+ libc.src.stdlib.abort
+ libc.src.stdlib.abs
+ libc.src.stdlib.aligned_alloc
+ libc.src.stdlib.atexit
+ libc.src.stdlib.atof
+ libc.src.stdlib.atoi
+ libc.src.stdlib.atol
+ libc.src.stdlib.atoll
+ libc.src.stdlib.bsearch
+ libc.src.stdlib.calloc
+ libc.src.stdlib.div
+ libc.src.stdlib.exit
+ libc.src.stdlib.free
+ libc.src.stdlib.l64a
+ libc.src.stdlib.labs
+ libc.src.stdlib.ldiv
+ libc.src.stdlib.llabs
+ libc.src.stdlib.lldiv
+ libc.src.stdlib.malloc
+ libc.src.stdlib.malloc_usable_size
+ libc.src.stdlib.memalignment
+ libc.src.stdlib.qsort
+ libc.src.stdlib.qsort_r
+ libc.src.stdlib.rand
+ libc.src.stdlib.realloc
+ libc.src.stdlib.srand
+ # libc.src.stdlib.strfromd
+ # libc.src.stdlib.strfromf
+ # libc.src.stdlib.strfroml
+ 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 entrypoints
+ libc.src.stdlib.strtod_l
+ libc.src.stdlib.strtof_l
+ libc.src.stdlib.strtol_l
+ libc.src.stdlib.strtold_l
+ libc.src.stdlib.strtoll_l
+ libc.src.stdlib.strtoul_l
+ libc.src.stdlib.strtoull_l
+
+ # time.h entrypoints
+ libc.src.time.asctime
+ libc.src.time.asctime_r
+ libc.src.time.ctime
+ libc.src.time.ctime_r
+ libc.src.time.difftime
+ libc.src.time.gmtime
+ libc.src.time.gmtime_r
+ libc.src.time.localtime
+ libc.src.time.localtime_r
+ libc.src.time.mktime
+ libc.src.time.strftime
+ libc.src.time.strftime_l
+ libc.src.time.timespec_get
+
+ # wchar.h entrypoints
+ libc.src.wchar.btowc
+ libc.src.wchar.wcslen
+ libc.src.wchar.wctob
+
+ # wctype.h entrypoints
+ libc.src.wctype.iswalpha
+ libc.src.wctype.iswgraph
+ libc.src.wctype.iswcntrl
+ libc.src.wctype.iswdigit
+ libc.src.wctype.iswupper
+ libc.src.wctype.iswalnum
+ libc.src.wctype.iswlower
+ libc.src.wctype.iswspace
+ libc.src.wctype.iswblank
+ libc.src.wctype.iswxdigit
+ libc.src.wctype.iswpunct
+ libc.src.wctype.iswprint
+ libc.src.wctype.iswctype
+ libc.src.wctype.wctype
+
+ # internal entrypoints
+ libc.startup.baremetal.init
+ libc.startup.baremetal.fini
+)
+
+set(TARGET_LIBM_ENTRYPOINTS
+ # complex.h entrypoints
+ libc.src.complex.cabs
+ libc.src.complex.cabsf
+ libc.src.complex.carg
+ libc.src.complex.cargf
+ libc.src.complex.creal
+ libc.src.complex.crealf
+ libc.src.complex.creall
+ libc.src.complex.cimag
+ libc.src.complex.cimagf
+ libc.src.complex.cimagl
+ libc.src.complex.conj
+ libc.src.complex.conjf
+ libc.src.complex.conjl
+ libc.src.complex.cproj
+ libc.src.complex.cprojf
+ libc.src.complex.cprojl
+
+ # 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.feraiseexcept
+ libc.src.fenv.fesetenv
+ libc.src.fenv.fesetexcept
+ libc.src.fenv.fesetexceptflag
+ libc.src.fenv.fesetround
+ libc.src.fenv.fetestexcept
+ libc.src.fenv.fetestexceptflag
+ libc.src.fenv.feupdateenv
+
+ # math.h entrypoints
+ libc.src.math.acosf
+ libc.src.math.acoshf
+ libc.src.math.acospif
+ libc.src.math.asinf
+ libc.src.math.asinhf
+ libc.src.math.asinpi
+ libc.src.math.asinpif
+ libc.src.math.atan2
+ libc.src.math.atan2f
+ # libc.src.math.atan2l
+ libc.src.math.atan
+ libc.src.math.atanf
+ libc.src.math.atanhf
+ libc.src.math.canonicalize
+ libc.src.math.canonicalizef
+ libc.src.math.canonicalizel
+ libc.src.math.cbrt
+ libc.src.math.cbrtf
+ libc.src.math.cbrtbf16
+ libc.src.math.ceil
+ libc.src.math.ceilf
+ libc.src.math.ceill
+ libc.src.math.copysign
+ libc.src.math.copysignf
+ libc.src.math.copysignl
+ libc.src.math.cos
+ libc.src.math.cosf
+ libc.src.math.coshf
+ libc.src.math.cospif
+ libc.src.math.dfmal
+ libc.src.math.dmull
+ libc.src.math.dsqrtl
+ libc.src.math.daddl
+ libc.src.math.ddivl
+ libc.src.math.dsubl
+ libc.src.math.erff
+ libc.src.math.exp
+ libc.src.math.exp10
+ libc.src.math.exp10f
+ libc.src.math.exp10m1f
+ libc.src.math.exp2
+ libc.src.math.exp2f
+ libc.src.math.exp2m1f
+ libc.src.math.expf
+ libc.src.math.expm1
+ libc.src.math.expm1f
+ libc.src.math.fabs
+ libc.src.math.fabsf
+ libc.src.math.fabsl
+ libc.src.math.fadd
+ libc.src.math.faddl
+ libc.src.math.fadd
+ libc.src.math.fdim
+ libc.src.math.fdimf
+ libc.src.math.fdiml
+ libc.src.math.fdiv
+ libc.src.math.fdivl
+ libc.src.math.ffma
+ libc.src.math.ffmal
+ libc.src.math.floor
+ libc.src.math.floorf
+ libc.src.math.floorl
+ libc.src.math.fma
+ libc.src.math.fmabf16
+ libc.src.math.fmaf
+ libc.src.math.fmax
+ libc.src.math.fmaxf
+ libc.src.math.fmaximum
+ libc.src.math.fmaximum_mag
+ libc.src.math.fmaximum_mag_num
+ libc.src.math.fmaximum_mag_numf
+ libc.src.math.fmaximum_mag_numl
+ libc.src.math.fmaximum_magf
+ libc.src.math.fmaximum_magl
+ libc.src.math.fmaximum_num
+ libc.src.math.fmaximum_numf
+ libc.src.math.fmaximum_numl
+ libc.src.math.fmaximumf
+ libc.src.math.fmaximuml
+ libc.src.math.fmaxl
+ libc.src.math.fmin
+ libc.src.math.fminf
+ libc.src.math.fminimum
+ libc.src.math.fminimum_mag
+ libc.src.math.fminimum_mag_num
+ libc.src.math.fminimum_mag_numf
+ libc.src.math.fminimum_mag_numl
+ libc.src.math.fminimum_magf
+ libc.src.math.fminimum_magl
+ libc.src.math.fminimum_num
+ libc.src.math.fminimum_numf
+ libc.src.math.fminimum_numl
+ libc.src.math.fminimumf
+ libc.src.math.fminimuml
+ libc.src.math.fminl
+ libc.src.math.fmod
+ libc.src.math.fmodf
+ # libc.src.math.fmodl
+ libc.src.math.fmul
+ libc.src.math.fmull
+ libc.src.math.frexp
+ libc.src.math.frexpf
+ libc.src.math.frexpl
+ libc.src.math.fromfp
+ libc.src.math.fromfpf
+ libc.src.math.fromfpl
+ libc.src.math.fromfpx
+ libc.src.math.fromfpxf
+ libc.src.math.fromfpxl
+ libc.src.math.fsqrt
+ libc.src.math.fsqrtl
+ libc.src.math.fsub
+ libc.src.math.fsubl
+ libc.src.math.getpayload
+ libc.src.math.getpayloadf
+ libc.src.math.getpayloadl
+ libc.src.math.hypot
+ libc.src.math.hypotf
+ libc.src.math.ilogb
+ libc.src.math.ilogbf
+ libc.src.math.ilogbl
+ libc.src.math.iscanonical
+ libc.src.math.iscanonicalf
+ libc.src.math.iscanonicall
+ libc.src.math.isnan
+ libc.src.math.isnanf
+ libc.src.math.isnanl
+ libc.src.math.issignaling
+ libc.src.math.issignalingf
+ libc.src.math.issignalingl
+ libc.src.math.ldexp
+ libc.src.math.ldexpf
+ libc.src.math.ldexpl
+ libc.src.math.llogb
+ libc.src.math.llogbf
+ libc.src.math.llogbl
+ 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.log
+ 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.logb
+ libc.src.math.logbf
+ libc.src.math.logbl
+ libc.src.math.logf
+ 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.nan
+ libc.src.math.nanf
+ libc.src.math.nanl
+ 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.nextdown
+ libc.src.math.nextdownf
+ libc.src.math.nextdownl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
+ libc.src.math.nextup
+ libc.src.math.nextupf
+ libc.src.math.nextupl
+ libc.src.math.pow
+ libc.src.math.powf
+ libc.src.math.remainder
+ libc.src.math.remainderf
+ libc.src.math.remainderl
+ libc.src.math.remquo
+ libc.src.math.remquof
+ libc.src.math.remquol
+ libc.src.math.rint
+ libc.src.math.rintf
+ libc.src.math.rintl
+ libc.src.math.round
+ libc.src.math.roundeven
+ libc.src.math.roundevenf
+ libc.src.math.roundevenl
+ libc.src.math.roundf
+ libc.src.math.roundl
+ libc.src.math.scalbln
+ libc.src.math.scalblnf
+ libc.src.math.scalblnl
+ libc.src.math.scalbn
+ libc.src.math.scalbnf
+ libc.src.math.scalbnl
+ libc.src.math.setpayload
+ libc.src.math.setpayloadf
+ libc.src.math.setpayloadl
+ libc.src.math.setpayloadsig
+ libc.src.math.setpayloadsigf
+ libc.src.math.setpayloadsigl
+ libc.src.math.sin
+ libc.src.math.sincos
+ libc.src.math.sincosf
+ libc.src.math.sinf
+ libc.src.math.sinhf
+ libc.src.math.sinpif
+ libc.src.math.sqrt
+ libc.src.math.sqrtf
+ libc.src.math.sqrtl
+ libc.src.math.tan
+ libc.src.math.tanf
+ libc.src.math.tanhf
+ libc.src.math.totalorder
+ libc.src.math.totalorderf
+ libc.src.math.totalorderl
+ libc.src.math.totalordermag
+ libc.src.math.totalordermagf
+ libc.src.math.totalordermagl
+ libc.src.math.trunc
+ libc.src.math.truncf
+ libc.src.math.truncl
+ libc.src.math.ufromfp
+ libc.src.math.ufromfpf
+ libc.src.math.ufromfpl
+ libc.src.math.ufromfpx
+ libc.src.math.ufromfpxf
+ libc.src.math.ufromfpxl
+)
+
+if(LIBC_TYPES_HAS_CFLOAT16)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # complex.h C23 _Complex _Float16 entrypoints
+ libc.src.complex.crealf16
+ libc.src.complex.cimagf16
+ libc.src.complex.conjf16
+ libc.src.complex.cprojf16
+ )
+endif()
+
+if(LIBC_TYPES_HAS_FLOAT16)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # math.h C23 _Float16 entrypoints
+ libc.src.math.acosf16
+ libc.src.math.acoshf16
+ libc.src.math.asinf16
+ libc.src.math.asinhf16
+ libc.src.math.atan2f16
+ libc.src.math.canonicalizef16
+ libc.src.math.cbrtf16
+ libc.src.math.ceilf16
+ libc.src.math.copysignf16
+ libc.src.math.cosf16
+ libc.src.math.coshf16
+ libc.src.math.cospif16
+ libc.src.math.exp10f16
+ libc.src.math.exp10m1f16
+ libc.src.math.exp2f16
+ libc.src.math.exp2m1f16
+ libc.src.math.expf16
+ libc.src.math.expm1f16
+ libc.src.math.f16add
+ libc.src.math.f16addf
+ libc.src.math.f16addl
+ libc.src.math.f16div
+ libc.src.math.f16divf
+ libc.src.math.f16divl
+ libc.src.math.f16fma
+ libc.src.math.f16fmaf
+ libc.src.math.f16fmal
+ libc.src.math.f16mul
+ libc.src.math.f16mulf
+ libc.src.math.f16mull
+ libc.src.math.f16sqrt
+ libc.src.math.f16sqrtf
+ libc.src.math.f16sqrtl
+ libc.src.math.f16sub
+ libc.src.math.f16subf
+ libc.src.math.f16subl
+ libc.src.math.fabsf16
+ libc.src.math.fdimf16
+ libc.src.math.floorf16
+ libc.src.math.fmaf16
+ libc.src.math.fmaxf16
+ libc.src.math.fmaximum_mag_numf16
+ libc.src.math.fmaximum_magf16
+ libc.src.math.fmaximum_numf16
+ libc.src.math.fmaximumf16
+ libc.src.math.fminf16
+ libc.src.math.fminimum_mag_numf16
+ libc.src.math.fminimum_magf16
+ libc.src.math.fminimum_numf16
+ libc.src.math.fminimumf16
+ libc.src.math.fmodf16
+ libc.src.math.frexpf16
+ libc.src.math.fromfpf16
+ libc.src.math.fromfpxf16
+ libc.src.math.getpayloadf16
+ libc.src.math.hypotf16
+ libc.src.math.ilogbf16
+ libc.src.math.iscanonicalf16
+ libc.src.math.isnanf16
+ libc.src.math.issignalingf16
+ libc.src.math.ldexpf16
+ libc.src.math.lgammaf16
+ libc.src.math.llogbf16
+ libc.src.math.llrintf16
+ libc.src.math.llroundf16
+ libc.src.math.log10f16
+ libc.src.math.log10p1f16
+ libc.src.math.log2f16
+ libc.src.math.log2p1f16
+ libc.src.math.logbf16
+ libc.src.math.logf16
+ libc.src.math.lrintf16
+ libc.src.math.lroundf16
+ libc.src.math.modff16
+ libc.src.math.nanf16
+ libc.src.math.nearbyintf16
+ libc.src.math.nextafterf16
+ libc.src.math.nextdownf16
+ libc.src.math.nexttowardf16
+ libc.src.math.nextupf16
+ libc.src.math.remainderf16
+ libc.src.math.remquof16
+ libc.src.math.rintf16
+ libc.src.math.roundevenf16
+ libc.src.math.roundf16
+ libc.src.math.scalblnf16
+ libc.src.math.scalbnf16
+ libc.src.math.setpayloadf16
+ libc.src.math.setpayloadsigf16
+ libc.src.math.sinf16
+ libc.src.math.sinhf16
+ libc.src.math.sinpif16
+ libc.src.math.sqrtf16
+ libc.src.math.tanf16
+ libc.src.math.tanhf16
+ libc.src.math.tanpif16
+ libc.src.math.totalorderf16
+ libc.src.math.totalordermagf16
+ libc.src.math.truncf16
+ libc.src.math.ufromfpf16
+ libc.src.math.ufromfpxf16
+ )
+
+ if(LIBC_TYPES_HAS_FLOAT128)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # math.h C23 mixed _Float16 and _Float128 entrypoints
+ libc.src.math.f16addf128
+ libc.src.math.f16divf128
+ libc.src.math.f16fmaf128
+ libc.src.math.f16mulf128
+ libc.src.math.f16sqrtf128
+ libc.src.math.f16subf128
+ )
+ endif()
+endif()
+
+if(LIBC_TYPES_HAS_CFLOAT128)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # complex.h C23 _Complex _Float128 entrypoints
+ libc.src.complex.crealf128
+ libc.src.complex.cimagf128
+ libc.src.complex.conjf128
+ libc.src.complex.cprojf128
+ )
+endif()
+
+if(LIBC_TYPES_HAS_FLOAT128)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # math.h C23 _Float128 entrypoints
+ libc.src.math.atan2f128
+ libc.src.math.canonicalizef128
+ libc.src.math.ceilf128
+ libc.src.math.copysignf128
+ libc.src.math.daddf128
+ libc.src.math.ddivf128
+ libc.src.math.dfmaf128
+ libc.src.math.dmulf128
+ libc.src.math.dsqrtf128
+ libc.src.math.dsubf128
+ libc.src.math.fabsf128
+ libc.src.math.faddf128
+ libc.src.math.fdimf128
+ libc.src.math.fdivf128
+ libc.src.math.ffmaf128
+ libc.src.math.floorf128
+ libc.src.math.fmaxf128
+ libc.src.math.fmaximum_mag_numf128
+ libc.src.math.fmaximum_magf128
+ libc.src.math.fmaximum_numf128
+ libc.src.math.fmaximumf128
+ libc.src.math.fminf128
+ libc.src.math.fminimum_mag_numf128
+ libc.src.math.fminimum_magf128
+ libc.src.math.fminimum_numf128
+ libc.src.math.fminimumf128
+ # libc.src.math.fmodf128
+ libc.src.math.fmulf128
+ libc.src.math.frexpf128
+ libc.src.math.fromfpf128
+ libc.src.math.fromfpxf128
+ libc.src.math.fsqrtf128
+ libc.src.math.fsubf128
+ libc.src.math.getpayloadf128
+ libc.src.math.ilogbf128
+ libc.src.math.iscanonicalf128
+ libc.src.math.isnanf128
+ libc.src.math.issignalingf128
+ libc.src.math.ldexpf128
+ libc.src.math.llogbf128
+ libc.src.math.llrintf128
+ libc.src.math.llroundf128
+ libc.src.math.logbf128
+ libc.src.math.lrintf128
+ libc.src.math.lroundf128
+ libc.src.math.modff128
+ libc.src.math.nanf128
+ libc.src.math.nearbyintf128
+ libc.src.math.nextafterf128
+ libc.src.math.nextdownf128
+ libc.src.math.nextupf128
+ libc.src.math.remainderf128
+ libc.src.math.remquof128
+ libc.src.math.rintf128
+ libc.src.math.roundevenf128
+ libc.src.math.roundf128
+ libc.src.math.scalblnf128
+ libc.src.math.scalbnf128
+ libc.src.math.setpayloadf128
+ libc.src.math.setpayloadsigf128
+ libc.src.math.sqrtf128
+ libc.src.math.totalorderf128
+ libc.src.math.totalordermagf128
+ libc.src.math.truncf128
+ libc.src.math.ufromfpf128
+ libc.src.math.ufromfpxf128
+ )
+endif()
+
+list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # bfloat16 entrypoints
+ libc.src.math.atanbf16
+ libc.src.math.acosbf16
+ libc.src.math.asinbf16
+ libc.src.math.bf16add
+ libc.src.math.bf16addf
+ libc.src.math.bf16addl
+ libc.src.math.bf16div
+ libc.src.math.bf16divf
+ libc.src.math.bf16divl
+ libc.src.math.bf16fma
+ libc.src.math.bf16fmaf
+ libc.src.math.bf16fmal
+ libc.src.math.bf16mul
+ libc.src.math.bf16mulf
+ libc.src.math.bf16mull
+ libc.src.math.bf16sub
+ libc.src.math.bf16subf
+ libc.src.math.bf16subl
+ libc.src.math.canonicalizebf16
+ libc.src.math.ceilbf16
+ libc.src.math.copysignbf16
+ libc.src.math.expbf16
+ libc.src.math.fabsbf16
+ libc.src.math.fdimbf16
+ libc.src.math.floorbf16
+ libc.src.math.fmaxbf16
+ libc.src.math.fmaximumbf16
+ libc.src.math.fmaximum_magbf16
+ libc.src.math.fmaximum_mag_numbf16
+ libc.src.math.fmaximum_numbf16
+ libc.src.math.fminbf16
+ libc.src.math.fminimumbf16
+ libc.src.math.fminimum_magbf16
+ libc.src.math.fminimum_mag_numbf16
+ libc.src.math.fminimum_numbf16
+ libc.src.math.fmodbf16
+ libc.src.math.frexpbf16
+ libc.src.math.fromfpbf16
+ libc.src.math.fromfpxbf16
+ libc.src.math.getpayloadbf16
+ libc.src.math.hypotbf16
+ libc.src.math.ilogbbf16
+ libc.src.math.iscanonicalbf16
+ libc.src.math.issignalingbf16
+ libc.src.math.ldexpbf16
+ libc.src.math.llogbbf16
+ libc.src.math.llrintbf16
+ libc.src.math.llroundbf16
+ libc.src.math.log_bf16
+ libc.src.math.logbbf16
+ libc.src.math.lrintbf16
+ libc.src.math.lroundbf16
+ libc.src.math.modfbf16
+ libc.src.math.nanbf16
+ libc.src.math.nearbyintbf16
+ libc.src.math.nextafterbf16
+ libc.src.math.nextdownbf16
+ libc.src.math.nexttowardbf16
+ libc.src.math.nextupbf16
+ libc.src.math.remainderbf16
+ libc.src.math.remquobf16
+ libc.src.math.rintbf16
+ libc.src.math.roundbf16
+ libc.src.math.roundevenbf16
+ libc.src.math.scalblnbf16
+ libc.src.math.scalbnbf16
+ libc.src.math.setpayloadbf16
+ libc.src.math.setpayloadsigbf16
+ libc.src.math.sqrtbf16
+ libc.src.math.tanbf16
+ libc.src.math.truncbf16
+ libc.src.math.totalorderbf16
+ libc.src.math.totalordermagbf16
+ libc.src.math.ufromfpbf16
+ libc.src.math.ufromfpxbf16
+)
+
+if(LIBC_TYPES_HAS_FLOAT128)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # math.h C++23 mixed bfloat16 and _Float128 entrypoints
+ libc.src.math.bf16addf128
+ libc.src.math.bf16divf128
+ libc.src.math.bf16fmaf128
+ libc.src.math.bf16mulf128
+ libc.src.math.bf16subf128
+ )
+endif()
+
+if(LIBC_COMPILER_HAS_FIXED_POINT)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # stdfix.h _Fract and _Accum entrypoints
+ libc.src.stdfix.abshk
+ libc.src.stdfix.abshr
+ libc.src.stdfix.absk
+ libc.src.stdfix.abslk
+ libc.src.stdfix.abslr
+ libc.src.stdfix.absr
+ libc.src.stdfix.exphk
+ libc.src.stdfix.expk
+ libc.src.stdfix.roundhk
+ libc.src.stdfix.roundhr
+ libc.src.stdfix.roundk
+ libc.src.stdfix.roundlk
+ libc.src.stdfix.roundlr
+ libc.src.stdfix.roundr
+ libc.src.stdfix.rounduhk
+ libc.src.stdfix.rounduhr
+ libc.src.stdfix.rounduk
+ libc.src.stdfix.roundulk
+ libc.src.stdfix.roundulr
+ libc.src.stdfix.roundur
+ libc.src.stdfix.sqrtuhk
+ libc.src.stdfix.sqrtuhr
+ libc.src.stdfix.sqrtuk
+ libc.src.stdfix.sqrtur
+ # libc.src.stdfix.sqrtulk
+ libc.src.stdfix.sqrtulr
+ libc.src.stdfix.uhksqrtus
+ libc.src.stdfix.uksqrtui
+ libc.src.stdfix.hrbits
+ libc.src.stdfix.uhrbits
+ libc.src.stdfix.rbits
+ libc.src.stdfix.urbits
+ libc.src.stdfix.lrbits
+ libc.src.stdfix.ulrbits
+ libc.src.stdfix.hkbits
+ libc.src.stdfix.uhkbits
+ libc.src.stdfix.kbits
+ libc.src.stdfix.ukbits
+ libc.src.stdfix.lkbits
+ libc.src.stdfix.ulkbits
+ libc.src.stdfix.bitshr
+ libc.src.stdfix.bitsr
+ libc.src.stdfix.bitslr
+ libc.src.stdfix.bitshk
+ libc.src.stdfix.bitsk
+ libc.src.stdfix.bitslk
+ libc.src.stdfix.bitsuhr
+ libc.src.stdfix.bitsur
+ libc.src.stdfix.bitsulr
+ libc.src.stdfix.bitsuhk
+ libc.src.stdfix.bitsuk
+ libc.src.stdfix.bitsulk
+ libc.src.stdfix.countlshr
+ libc.src.stdfix.countlsr
+ libc.src.stdfix.countlslr
+ libc.src.stdfix.countlshk
+ libc.src.stdfix.countlsk
+ libc.src.stdfix.countlslk
+ libc.src.stdfix.countlsuhr
+ libc.src.stdfix.countlsur
+ libc.src.stdfix.countlsulr
+ libc.src.stdfix.countlsuhk
+ libc.src.stdfix.countlsuk
+ libc.src.stdfix.countlsulk
+ libc.src.stdfix.idivr
+ libc.src.stdfix.idivlr
+ libc.src.stdfix.idivk
+ libc.src.stdfix.idivlk
+ libc.src.stdfix.idivur
+ libc.src.stdfix.idivulr
+ libc.src.stdfix.idivuk
+ libc.src.stdfix.idivulk
+ libc.src.stdfix.divir
+ libc.src.stdfix.divilr
+ libc.src.stdfix.divik
+ libc.src.stdfix.divilk
+ libc.src.stdfix.diviur
+ libc.src.stdfix.diviulr
+ libc.src.stdfix.diviuk
+ libc.src.stdfix.diviulk
+ )
+endif()
+
+if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
+ list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # regex.h entrypoints
+ libc.src.regex.regcomp
+ libc.src.regex.regexec
+ libc.src.regex.regerror
+ libc.src.regex.regfree
+ )
+endif()
+
+set(TARGET_LLVMLIBC_ENTRYPOINTS
+ ${TARGET_LIBC_ENTRYPOINTS}
+ ${TARGET_LIBM_ENTRYPOINTS}
+)
diff --git a/libc/config/baremetal/hexagon/headers.txt b/libc/config/baremetal/hexagon/headers.txt
new file mode 100644
index 0000000000000..a69660a97fdae
--- /dev/null
+++ b/libc/config/baremetal/hexagon/headers.txt
@@ -0,0 +1,32 @@
+set(TARGET_PUBLIC_HEADERS
+ libc.include.assert
+ libc.include.complex
+ libc.include.ctype
+ libc.include.elf
+ libc.include.errno
+ libc.include.features
+ libc.include.fenv
+ libc.include.float
+ libc.include.inttypes
+ libc.include.limits
+ libc.include.locale
+ libc.include.math
+ libc.include.setjmp
+ libc.include.stdbit
+ libc.include.stdckdint
+ libc.include.stdfix
+ libc.include.stdint
+ libc.include.stdio
+ libc.include.stdlib
+ libc.include.string
+ libc.include.strings
+ libc.include.sys_queue
+ libc.include.time
+ libc.include.uchar
+ libc.include.wchar
+ libc.include.wctype
+)
+
+if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
+ list(APPEND TARGET_PUBLIC_HEADERS libc.include.regex)
+endif()
diff --git a/libc/include/llvm-libc-types/__jmp_buf.h b/libc/include/llvm-libc-types/__jmp_buf.h
index a80afa2e6b815..ed5f1d7cab35f 100644
--- a/libc/include/llvm-libc-types/__jmp_buf.h
+++ b/libc/include/llvm-libc-types/__jmp_buf.h
@@ -60,6 +60,12 @@ typedef struct {
#if __ARM_FP
long fopaque[8]; // d8-d15
#endif
+#elif defined(__hexagon__)
+ // Callee-saved registers r16-r27, followed by sp (r29), fp (r30) and lr
+ // (r31). r16-r27 are saved and restored as register pairs using memd, which
+ // requires the buffer to be 8-byte aligned, hence long long rather than
+ // long. That also rounds the size up, leaving one word of tail padding.
+ long long opaque[8];
#else
#error "__jmp_buf not available for your target architecture."
#endif
diff --git a/libc/include/llvm-libc-types/fenv_t.h b/libc/include/llvm-libc-types/fenv_t.h
index 2cfeff7b8a9f8..fab3e4475883a 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__) || defined(__SPIRV__)
typedef struct {
unsigned int __fpc;
diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h
index 46572260cbc9e..7a3af0f22eb07 100644
--- a/libc/src/__support/FPUtil/FEnvImpl.h
+++ b/libc/src/__support/FPUtil/FEnvImpl.h
@@ -118,6 +118,8 @@ LIBC_INLINE int set_env(const fenv_t *env) {
#include "arm/FEnvImpl.h"
#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) && defined(__riscv_flen)
#include "riscv/FEnvImpl.h"
+#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
+#include "hexagon/FEnvImpl.h"
#else
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/__support/FPUtil/hexagon/FEnvImpl.h b/libc/src/__support/FPUtil/hexagon/FEnvImpl.h
new file mode 100644
index 0000000000000..1dc72d1bcc8d9
--- /dev/null
+++ b/libc/src/__support/FPUtil/hexagon/FEnvImpl.h
@@ -0,0 +1,210 @@
+//===-- hexagon floating point env manipulation functions -------*- 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_FPUTIL_HEXAGON_FENVIMPL_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_HEXAGON_FENVIMPL_H
+
+#include "hdr/fenv_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/fenv_t.h"
+#include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM
+#include "src/__support/macros/config.h" // For LIBC_INLINE
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+// Hexagon keeps all floating-point state in the User Status Register (USR):
+//
+// bits 5:1 sticky exception status flags
+// bit 1 FPINVF invalid
+// bit 2 FPDBZF divide-by-zero
+// bit 3 FPOVFF overflow
+// bit 4 FPUNFF underflow
+// bit 5 FPINPF inexact
+// bits 23:22 FPRND rounding mode
+// 00 round to nearest (ties to even)
+// 01 toward zero
+// 10 downward (toward -inf)
+// 11 upward (toward +inf)
+// bits 29:25 exception trap-enable bits (status flag << 24)
+// bit 25 FPINVE, bit 26 FPDBZE, bit 27 FPOVFE,
+// bit 28 FPUNFE, bit 29 FPINEE
+//
+// Note the hardware status/enable bit positions do NOT match the FE_* macro
+// values used by llvm-libc, so we translate between the two below.
+struct FEnv {
+ // Hardware status-flag bit positions within USR.
+ static constexpr uint32_t INVALID = 0x02; // bit 1
+ static constexpr uint32_t DIVBYZERO = 0x04; // bit 2
+ static constexpr uint32_t OVERFLOW = 0x08; // bit 3
+ static constexpr uint32_t UNDERFLOW = 0x10; // bit 4
+ static constexpr uint32_t INEXACT = 0x20; // bit 5
+ static constexpr uint32_t STATUS_MASK =
+ INVALID | DIVBYZERO | OVERFLOW | UNDERFLOW | INEXACT;
+
+ // The trap-enable bits sit STATUS bits shifted up by this amount.
+ static constexpr uint32_t ENABLE_SHIFT = 24;
+ static constexpr uint32_t ENABLE_MASK = STATUS_MASK << ENABLE_SHIFT;
+
+ // Rounding mode field.
+ static constexpr uint32_t RND_SHIFT = 22;
+ static constexpr uint32_t RND_MASK = 0x3;
+ static constexpr uint32_t RND_TONEAREST = 0x0;
+ static constexpr uint32_t RND_TOWARDZERO = 0x1;
+ static constexpr uint32_t RND_DOWNWARD = 0x2;
+ static constexpr uint32_t RND_UPWARD = 0x3;
+
+ // Combined mask of all FP-relevant USR bits. fegetenv/fesetenv only touch
+ // these so that non-FP USR fields (loop counters, prefetch state, etc.) are
+ // never disturbed.
+ static constexpr uint32_t FP_MASK =
+ STATUS_MASK | (RND_MASK << RND_SHIFT) | ENABLE_MASK;
+
+ LIBC_INLINE static uint32_t get_usr() {
+ uint32_t usr;
+ LIBC_INLINE_ASM("%0 = usr\n\t" : "=r"(usr));
+ return usr;
+ }
+
+ LIBC_INLINE static void set_usr(uint32_t usr) {
+ LIBC_INLINE_ASM("usr = %0\n\t" : : "r"(usr));
+ }
+
+ // Translate a set of FE_* exception macros into hardware status-flag bits.
+ LIBC_INLINE static uint32_t exception_macro_to_bits(int except) {
+ return ((except & FE_INVALID) ? INVALID : 0) |
+ ((except & FE_DIVBYZERO) ? DIVBYZERO : 0) |
+ ((except & FE_OVERFLOW) ? OVERFLOW : 0) |
+ ((except & FE_UNDERFLOW) ? UNDERFLOW : 0) |
+ ((except & FE_INEXACT) ? INEXACT : 0);
+ }
+
+ // Translate hardware status-flag bits back into FE_* exception macros.
+ LIBC_INLINE static int exception_bits_to_macro(uint32_t status) {
+ return ((status & INVALID) ? FE_INVALID : 0) |
+ ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) |
+ ((status & OVERFLOW) ? FE_OVERFLOW : 0) |
+ ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) |
+ ((status & INEXACT) ? FE_INEXACT : 0);
+ }
+};
+
+LIBC_INLINE int enable_except(int excepts) {
+ uint32_t usr = FEnv::get_usr();
+ uint32_t old_enabled = (usr >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK;
+ uint32_t new_enabled = old_enabled | FEnv::exception_macro_to_bits(excepts);
+ FEnv::set_usr((usr & ~FEnv::ENABLE_MASK) |
+ (new_enabled << FEnv::ENABLE_SHIFT));
+ return FEnv::exception_bits_to_macro(old_enabled);
+}
+
+LIBC_INLINE int disable_except(int excepts) {
+ uint32_t usr = FEnv::get_usr();
+ uint32_t old_enabled = (usr >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK;
+ uint32_t new_enabled = old_enabled & ~FEnv::exception_macro_to_bits(excepts);
+ FEnv::set_usr((usr & ~FEnv::ENABLE_MASK) |
+ (new_enabled << FEnv::ENABLE_SHIFT));
+ return FEnv::exception_bits_to_macro(old_enabled);
+}
+
+LIBC_INLINE int get_except() {
+ uint32_t enabled =
+ (FEnv::get_usr() >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK;
+ return FEnv::exception_bits_to_macro(enabled);
+}
+
+LIBC_INLINE int clear_except(int excepts) {
+ uint32_t usr = FEnv::get_usr();
+ usr &= ~FEnv::exception_macro_to_bits(excepts);
+ FEnv::set_usr(usr);
+ return 0;
+}
+
+LIBC_INLINE int test_except(int excepts) {
+ uint32_t to_test = FEnv::exception_macro_to_bits(excepts);
+ uint32_t status = FEnv::get_usr() & FEnv::STATUS_MASK;
+ return FEnv::exception_bits_to_macro(status & to_test);
+}
+
+LIBC_INLINE int set_except(int excepts) {
+ uint32_t usr = FEnv::get_usr();
+ FEnv::set_usr(usr | FEnv::exception_macro_to_bits(excepts));
+ return 0;
+}
+
+LIBC_INLINE int raise_except(int excepts) {
+ // Setting the sticky status flag triggers a trap if the corresponding
+ // enable bit is set; otherwise it simply records the exception.
+ uint32_t usr = FEnv::get_usr();
+ FEnv::set_usr(usr | FEnv::exception_macro_to_bits(excepts));
+ return 0;
+}
+
+LIBC_INLINE int get_round() {
+ uint32_t rm = (FEnv::get_usr() >> FEnv::RND_SHIFT) & FEnv::RND_MASK;
+ switch (rm) {
+ case FEnv::RND_TONEAREST:
+ return FE_TONEAREST;
+ case FEnv::RND_TOWARDZERO:
+ return FE_TOWARDZERO;
+ case FEnv::RND_DOWNWARD:
+ return FE_DOWNWARD;
+ case FEnv::RND_UPWARD:
+ return FE_UPWARD;
+ default:
+ return -1; // Error value.
+ }
+}
+
+LIBC_INLINE int set_round(int mode) {
+ uint32_t rm;
+ switch (mode) {
+ case FE_TONEAREST:
+ rm = FEnv::RND_TONEAREST;
+ break;
+ case FE_TOWARDZERO:
+ rm = FEnv::RND_TOWARDZERO;
+ break;
+ case FE_DOWNWARD:
+ rm = FEnv::RND_DOWNWARD;
+ break;
+ case FE_UPWARD:
+ rm = FEnv::RND_UPWARD;
+ break;
+ default:
+ return -1; // To indicate failure.
+ }
+ uint32_t usr = FEnv::get_usr();
+ FEnv::set_usr((usr & ~(FEnv::RND_MASK << FEnv::RND_SHIFT)) |
+ (rm << FEnv::RND_SHIFT));
+ return 0;
+}
+
+LIBC_INLINE int get_env(fenv_t *envp) {
+ uint32_t *state = reinterpret_cast<uint32_t *>(envp);
+ *state = FEnv::get_usr() & FEnv::FP_MASK;
+ return 0;
+}
+
+LIBC_INLINE int set_env(const fenv_t *envp) {
+ uint32_t usr = FEnv::get_usr();
+ if (envp == FE_DFL_ENV) {
+ // Default environment: round to nearest, no exceptions raised or enabled.
+ FEnv::set_usr(usr & ~FEnv::FP_MASK);
+ return 0;
+ }
+ uint32_t state = *reinterpret_cast<const uint32_t *>(envp);
+ // Preserve non-FP USR bits; only load the FP-relevant fields.
+ FEnv::set_usr((usr & ~FEnv::FP_MASK) | (state & FEnv::FP_MASK));
+ return 0;
+}
+
+} // namespace fputil
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_HEXAGON_FENVIMPL_H
diff --git a/libc/src/__support/macros/properties/architectures.h b/libc/src/__support/macros/properties/architectures.h
index f73fa7a7643ab..c1c425067ddd9 100644
--- a/libc/src/__support/macros/properties/architectures.h
+++ b/libc/src/__support/macros/properties/architectures.h
@@ -70,4 +70,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/memory_size.h b/libc/src/__support/memory_size.h
index 49c3598960885..f85956e0b11b3 100644
--- a/libc/src/__support/memory_size.h
+++ b/libc/src/__support/memory_size.h
@@ -47,8 +47,11 @@ class SafeMemSize {
type result;
if (LIBC_UNLIKELY((value | other.value) < 0)) {
result = -1;
- } else {
- result = value + other.value;
+ } else if (LIBC_UNLIKELY(add_overflow(value, other.value, result))) {
+ // Signed addition would overflow. Computing `value + other.value`
+ // directly is undefined behavior, so detect the overflow with the
+ // builtin and mark the result invalid instead.
+ result = -1;
}
return SafeMemSize{result};
}
diff --git a/libc/src/setjmp/hexagon/CMakeLists.txt b/libc/src/setjmp/hexagon/CMakeLists.txt
new file mode 100644
index 0000000000000..55c80b0bede0d
--- /dev/null
+++ b/libc/src/setjmp/hexagon/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_entrypoint_object(
+ setjmp
+ SRCS
+ setjmp.cpp
+ HDRS
+ ../setjmp_impl.h
+ DEPENDS
+ libc.hdr.types.jmp_buf
+)
+
+add_entrypoint_object(
+ longjmp
+ SRCS
+ longjmp.cpp
+ HDRS
+ ../longjmp.h
+ DEPENDS
+ libc.hdr.types.jmp_buf
+)
diff --git a/libc/src/setjmp/hexagon/longjmp.cpp b/libc/src/setjmp/hexagon/longjmp.cpp
new file mode 100644
index 0000000000000..aad260bba4606
--- /dev/null
+++ b/libc/src/setjmp/hexagon/longjmp.cpp
@@ -0,0 +1,35 @@
+//===-- 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/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Restore the registers saved by setjmp, see the comment there for the layout
+// of the buffer.
+[[gnu::naked]] LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf buf, int val)) {
+ asm(R"(
+ r17:16 = memd(r0+#0)
+ r19:18 = memd(r0+#8)
+ r21:20 = memd(r0+#16)
+ r23:22 = memd(r0+#24)
+ r25:24 = memd(r0+#32)
+ r27:26 = memd(r0+#40)
+ r29 = memw(r0+#48)
+ r30 = memw(r0+#52)
+ r31 = memw(r0+#56)
+
+ # return val ?: 1;
+ { p0 = cmp.eq(r1,#0); if (p0.new) r1 = #1 }
+ r0 = r1
+ jumpr r31)");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/hexagon/setjmp.cpp b/libc/src/setjmp/hexagon/setjmp.cpp
new file mode 100644
index 0000000000000..edf4c33aa6621
--- /dev/null
+++ b/libc/src/setjmp/hexagon/setjmp.cpp
@@ -0,0 +1,36 @@
+//===-- 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/__support/macros/config.h"
+#include "src/setjmp/setjmp_impl.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// The Hexagon ABI callee-saved registers are r16-r27. Those are stored as
+// register pairs, which requires the buffer to be 8-byte aligned. The stack
+// pointer (r29), frame pointer (r30) and link register (r31) are stored
+// individually; r28 is caller-saved so it does not need to be preserved.
+[[gnu::naked]] LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
+ asm(R"(
+ memd(r0+#0) = r17:16
+ memd(r0+#8) = r19:18
+ memd(r0+#16) = r21:20
+ memd(r0+#24) = r23:22
+ memd(r0+#32) = r25:24
+ memd(r0+#40) = r27:26
+ memw(r0+#48) = r29
+ memw(r0+#52) = r30
+ memw(r0+#56) = r31
+
+ # Return zero.
+ r0 = #0
+ jumpr r31)");
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/startup/baremetal/hexagon/CMakeLists.txt b/libc/startup/baremetal/hexagon/CMakeLists.txt
new file mode 100644
index 0000000000000..372731be765df
--- /dev/null
+++ b/libc/startup/baremetal/hexagon/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_startup_object(
+ crt1
+ SRC
+ start.cpp
+ DEPENDS
+ libc.src.stdlib.atexit
+ libc.src.stdlib.exit
+ libc.src.string.memcpy
+ libc.src.string.memset
+ libc.startup.baremetal.init
+ libc.startup.baremetal.fini
+)
diff --git a/libc/startup/baremetal/hexagon/start.cpp b/libc/startup/baremetal/hexagon/start.cpp
new file mode 100644
index 0000000000000..946cea86b42fb
--- /dev/null
+++ b/libc/startup/baremetal/hexagon/start.cpp
@@ -0,0 +1,95 @@
+//===-- 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 "hdr/stdint_proxy.h"
+#include "src/__support/macros/config.h"
+#include "src/stdlib/atexit.h"
+#include "src/stdlib/exit.h"
+#include "src/string/memcpy.h"
+#include "src/string/memset.h"
+#include "startup/baremetal/fini.h"
+#include "startup/baremetal/init.h"
+
+extern "C" {
+int main(int argc, char **argv);
+void _start();
+
+// Semihosting library initialisation if applicable. Required for printf, etc.
+[[gnu::weak]] void _platform_init() {}
+
+// These symbols are provided by the linker. The exact names are not defined by
+// a standard.
+extern uintptr_t __stack;
+extern uintptr_t __data_source[];
+extern uintptr_t __data_start[];
+extern uintptr_t __data_size[];
+extern uintptr_t __bss_start[];
+extern uintptr_t __bss_size[];
+} // extern "C"
+
+namespace LIBC_NAMESPACE_DECL {
+
+[[noreturn]] void do_start() {
+ // TODO: This startup code is the MVP for running under the Hexagon
+ // simulator with semihosting. It does not configure the MMU or caches.
+
+ // Clear the Supervisor Status Register so that a subsequent trap0
+ // semihosting call is serviced by the monitor.
+ asm volatile("ssr = %0" : : "r"(0));
+
+ // Perform the equivalent of scatterloading
+ LIBC_NAMESPACE::memcpy(__data_start, __data_source,
+ reinterpret_cast<uintptr_t>(__data_size));
+ LIBC_NAMESPACE::memset(__bss_start, '\0',
+ reinterpret_cast<uintptr_t>(__bss_size));
+ __libc_init_array();
+
+ _platform_init();
+ LIBC_NAMESPACE::atexit(&__libc_fini_array);
+ LIBC_NAMESPACE::exit(main(0, 0));
+}
+} // namespace LIBC_NAMESPACE_DECL
+
+extern "C" {
+[[gnu::section(".text.init.enter"), gnu::naked]]
+void _start() {
+ // Setup event vector base (needed for semihosting trap handling).
+ asm volatile("r0 = ##__llvm_libc_hexagon_event_vectors\n\t"
+ "evb = r0");
+ // Setup stack pointer, 16-byte aligned.
+ asm volatile("r0 = ##__stack\n\t"
+ "sp = and(r0, #-16)");
+ // Setup GP register for the small-data area.
+ asm volatile("r0 = ##_SDA_BASE_\n\t"
+ "gp = r0");
+ asm volatile("jump %0" : : "X"(LIBC_NAMESPACE::do_start));
+}
+} // extern "C"
+
+// The simulator services semihosting when trap0 is executed. Put the trap0
+// handler at event-vector slot 8; other slots are unexpected and spin.
+asm(".text\n\t"
+ ".p2align 4\n"
+ "__llvm_libc_hexagon_event_spin:\n\t"
+ "jump __llvm_libc_hexagon_event_spin\n"
+ "__llvm_libc_hexagon_event_trap0:\n\t"
+ "rte\n\t"
+ ".p2align 12, 0\n\t"
+ ".global __llvm_libc_hexagon_event_vectors\n"
+ "__llvm_libc_hexagon_event_vectors:\n\t"
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 0 reset
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 1 nmi
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 2 error
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 3 reserved
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 4 tlb miss x
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 5 reserved
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 6 tlb miss rw
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 7 reserved
+ "jump __llvm_libc_hexagon_event_trap0\n\t" // 8 trap0
+ "jump __llvm_libc_hexagon_event_spin\n\t" // 9 trap1
+);
diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt
index e6d978e16b46f..d62f747175e61 100644
--- a/libc/test/UnitTest/CMakeLists.txt
+++ b/libc/test/UnitTest/CMakeLists.txt
@@ -29,7 +29,7 @@ function(_create_unittest_framework_library fq_target_name)
${TEST_LIB_HDRS}
)
target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
- if(TARGET libc.src.time.clock)
+ if(libc.src.time.clock IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)
target_compile_definitions(${fq_target_name} PRIVATE TARGET_SUPPORTS_CLOCK)
endif()
@@ -125,11 +125,6 @@ add_unittest_framework_library(
.LibcTest
)
-set(libc_hermetic_test_support_srcs HermeticTestUtils.cpp)
-if(LIBC_TARGET_OS_IS_BAREMETAL AND LIBC_TARGET_ARCHITECTURE_IS_ARM)
- list(APPEND libc_hermetic_test_support_srcs ArmBaremetalTestUtils.cpp)
-endif()
-
if(LIBC_TEST_SUBPROCESS_TESTS)
set(libc_death_test_deps
libc.hdr.stdint_proxy
@@ -164,12 +159,27 @@ else()
)
endif()
+set(libc_hermetic_test_support_srcs HermeticTestUtils.cpp)
+set(libc_hermetic_test_support_deps libc.hdr.stdint_proxy)
+if(LIBC_TARGET_OS_IS_BAREMETAL)
+ if(LIBC_TARGET_ARCHITECTURE_IS_ARM)
+ list(APPEND libc_hermetic_test_support_srcs ArmBaremetalTestUtils.cpp)
+ elseif(LIBC_TARGET_ARCHITECTURE_IS_HEXAGON)
+ list(APPEND libc_hermetic_test_support_srcs HexagonBaremetalTestUtils.cpp)
+ endif()
+ list(APPEND libc_hermetic_test_support_deps
+ libc.hdr.types.size_t
+ libc.hdr.types.ssize_t
+ libc.hdr.types.struct_timespec
+ )
+endif()
+
add_unittest_framework_library(
HermeticTestUtils
SRCS
${libc_hermetic_test_support_srcs}
DEPENDS
- libc.hdr.stdint_proxy
+ ${libc_hermetic_test_support_deps}
)
add_header_library(
diff --git a/libc/test/UnitTest/HexagonBaremetalTestUtils.cpp b/libc/test/UnitTest/HexagonBaremetalTestUtils.cpp
new file mode 100644
index 0000000000000..a2bafe6ca9740
--- /dev/null
+++ b/libc/test/UnitTest/HexagonBaremetalTestUtils.cpp
@@ -0,0 +1,119 @@
+//===--- Hexagon bare-metal hermetic test utilities -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// llvm-libc's bare-metal port defers all OS interaction to a small set of
+// "vendor-provided" hook symbols (see
+// libc/src/__support/OSUtil/baremetal/io.h and the bare-metal time sources).
+// This file implements those hooks for the Hexagon simulator using Angel-style
+// semihosting, i.e. a `trap0(#0)` with:
+// R0 = system call code (also the return value)
+// R1 = pointer to an argument block (also errno on failure)
+// R2 = exit status (for SYS_EXIT only)
+// The read/write calls return the number of bytes NOT transferred.
+//
+// It is compiled into HermeticTestUtils so hermetic tests can run under
+// the simulator. It is purely test-support code and is not intended for use as
+// general-purpose semihosting support.
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "hdr/types/struct_timespec.h"
+
+namespace {
+
+enum HexagonSyscall {
+ SYS_WRITE = 5,
+ SYS_READ = 6,
+ SYS_TIME = 0x11,
+ SYS_EXIT = 24,
+};
+
+// Software interrupt used to enter the simulator monitor.
+#define HEXAGON_SWI "trap0(#0)"
+
+// Issue a semihosting call: R0 = code, R1 = pointer to argument block.
+// Returns the value the simulator places in R0.
+int hexagon_semihost(int code, size_t *args) {
+ register uintptr_t r0 __asm__("r0") = static_cast<uintptr_t>(code);
+ register uintptr_t r1 __asm__("r1") = reinterpret_cast<uintptr_t>(args);
+ __asm__ __volatile__(HEXAGON_SWI : "=r"(r0), "=r"(r1) : "r"(r0), "r"(r1));
+ return static_cast<int>(r0);
+}
+
+} // namespace
+
+extern "C" {
+
+// The cookie type/objects only need to exist; their contents encode the file
+// descriptor used by the simulator-backed implementation.
+struct __llvm_libc_stdio_cookie {
+ int fd;
+};
+
+__llvm_libc_stdio_cookie __llvm_libc_stdin_cookie = {0};
+__llvm_libc_stdio_cookie __llvm_libc_stdout_cookie = {1};
+__llvm_libc_stdio_cookie __llvm_libc_stderr_cookie = {2};
+
+ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf, size_t size) {
+ int fd = cookie ? static_cast<__llvm_libc_stdio_cookie *>(cookie)->fd : 1;
+ size_t args[] = {
+ static_cast<size_t>(fd),
+ reinterpret_cast<size_t>(buf),
+ size,
+ };
+ int not_written = hexagon_semihost(SYS_WRITE, args);
+ if (not_written < 0)
+ return -1;
+ // The simulator returns the number of bytes NOT written.
+ return static_cast<ssize_t>(size) - not_written;
+}
+
+ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size) {
+ int fd = cookie ? static_cast<__llvm_libc_stdio_cookie *>(cookie)->fd : 0;
+ size_t args[] = {
+ static_cast<size_t>(fd),
+ reinterpret_cast<size_t>(buf),
+ size,
+ };
+ int not_read = hexagon_semihost(SYS_READ, args);
+ if (not_read < 0)
+ return -1;
+ // The simulator returns the number of bytes NOT read.
+ return static_cast<ssize_t>(size) - not_read;
+}
+
+[[noreturn]] void __llvm_libc_exit(int status) {
+ // The simulator reads the exit status from R2 and the syscall code from R0.
+ register uintptr_t r2 __asm__("r2") = static_cast<uintptr_t>(status);
+ register uintptr_t r0 __asm__("r0") = SYS_EXIT;
+ __asm__ __volatile__(HEXAGON_SWI : : "r"(r0), "r"(r2) : "memory");
+ __builtin_unreachable();
+}
+
+// The bare-metal config builds with LIBC_ERRNO_MODE_EXTERNAL, so the vendor
+// must provide storage for errno via this hook.
+int *__llvm_libc_errno() {
+ static int errno_storage;
+ return &errno_storage;
+}
+
+// Vendor hook used by the bare-metal `timespec_get()` implementation. The
+// Hexagon simulator's SYS_TIME call returns wall-clock time in whole seconds
+// (R0 = code on entry, R0 = seconds on return).
+bool __llvm_libc_timespec_get_utc(struct timespec *ts) {
+ register uintptr_t r0 __asm__("r0") = SYS_TIME;
+ __asm__ __volatile__(HEXAGON_SWI : "=r"(r0) : "r"(r0));
+ ts->tv_sec = static_cast<time_t>(r0);
+ ts->tv_nsec = 0;
+ return true;
+}
+
+} // extern "C"
diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index 385f968ce2863..4fad25e368c51 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -195,11 +195,15 @@ int Test::runTests(const TestOptions &Options) {
tlog << green << "[ RUN ] " << reset << TestName << '\n';
RunContext Ctx;
internal::current_context = &Ctx;
- [[maybe_unused]] const uint64_t start_time = static_cast<uint64_t>(clock());
+#ifdef LIBC_TEST_USE_CLOCK
+ const uint64_t start_time = static_cast<uint64_t>(clock());
+#endif
T->SetUp();
T->Run();
T->TearDown();
- [[maybe_unused]] const uint64_t end_time = static_cast<uint64_t>(clock());
+#ifdef LIBC_TEST_USE_CLOCK
+ const uint64_t end_time = static_cast<uint64_t>(clock());
+#endif
internal::current_context = nullptr;
switch (Ctx.status()) {
case RunContext::RunResult::Fail:
diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index 2758d3ef83bab..f41ff5fdac769 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -526,6 +526,8 @@ CString libc_make_test_file_path_func(const char *file_name);
// EXPECT_DEATH can appear in a test of any function, e.g. checking for a crash
// if passing nullptr to the function. So it must be defined, even if it can't
// do anything.
+#define EXPECT_EXITS(FUNC, EXIT)
+#define ASSERT_EXITS(FUNC, EXIT)
#define EXPECT_DEATH(FUNC, SIG)
#define ASSERT_DEATH(FUNC, SIG)
diff --git a/libc/test/UnitTest/llvm-libc-baremetal.ld b/libc/test/UnitTest/llvm-libc-baremetal.ld
index e88a68cf62aa4..2f84d934edfe1 100644
--- a/libc/test/UnitTest/llvm-libc-baremetal.ld
+++ b/libc/test/UnitTest/llvm-libc-baremetal.ld
@@ -80,6 +80,9 @@ SECTIONS {
.data : ALIGN(8) {
PROVIDE(__data_start = .);
+ /* Base of the small-data area. Targets with GP-relative small-data
+ addressing (e.g. Hexagon) load GP with this at startup. */
+ PROVIDE(_SDA_BASE_ = .);
*(.data .data.* .gnu.linkonce.d.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(8);
diff --git a/libc/test/src/math/smoke/exp10m1f_test.cpp b/libc/test/src/math/smoke/exp10m1f_test.cpp
index 87320fa2fe2f0..6f51abbd19143 100644
--- a/libc/test/src/math/smoke/exp10m1f_test.cpp
+++ b/libc/test/src/math/smoke/exp10m1f_test.cpp
@@ -17,10 +17,13 @@ TEST_F(LlvmLibcExp10m1fTest, SpecialNumbers) {
EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::exp10m1f(sNaN), FE_INVALID);
EXPECT_MATH_ERRNO(0);
- EXPECT_EQ(FPBits(aNaN).uintval(),
- FPBits(LIBC_NAMESPACE::exp10m1f(aNaN)).uintval());
- EXPECT_EQ(FPBits(neg_aNaN).uintval(),
- FPBits(LIBC_NAMESPACE::exp10m1f(neg_aNaN)).uintval());
+ // Use EXPECT_FP_EQ (which treats any two NaNs as equal) rather than comparing
+ // raw bit patterns: exp10m1f(NaN) is computed as NaN + inf, and some targets
+ // (e.g. Hexagon) produce a non-canonical NaN encoding (0xFFFFFFFF) instead of
+ // the canonical quiet NaN. Both are valid NaNs, so only require NaN-ness
+ // here.
+ EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::exp10m1f(aNaN));
+ EXPECT_FP_EQ(neg_aNaN, LIBC_NAMESPACE::exp10m1f(neg_aNaN));
EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp10m1f(inf));
EXPECT_FP_EQ_ALL_ROUNDING(-1.0f, LIBC_NAMESPACE::exp10m1f(neg_inf));
EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::exp10m1f(zero));
More information about the libc-commits
mailing list