kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit af964d3659842b90e2f7aa868fd3f6051f366a8a
parent ed7f379593b1990849bff38040e04435222cb9b0
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 18 Jun 2026 13:12:26 -0700

rt: expand freestanding libc surface

Diffstat:
Art/include/inttypes.h | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrt/include/limits.h | 12++++++++++++
Art/include/stdbit.h | 417+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Art/include/stdckdint.h | 13+++++++++++++
Mrt/include/stddef.h | 3+++
Mrt/include/stdint.h | 43+++++++++++++++++++++++++++++++++++++++++++
Mrt/include/stdlib.h | 1+
Mrt/include/string.h | 7+++++++
Mrt/lib/mem/mem.c | 7+++++++
Mrt/lib/stdlib/stdlib.c | 36++++++++++++++++++++++++++++++++++++
Mrt/lib/string/string.c | 40++++++++++++++++++++++++++++++++++++++++
Mtest/rt/cases/freestanding_lib.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/rt/smoke.c | 28++++++++++++++++++++++++++++
13 files changed, 888 insertions(+), 0 deletions(-)

diff --git a/rt/include/inttypes.h b/rt/include/inttypes.h @@ -0,0 +1,216 @@ +/* inttypes.h -- integer format macros and greatest-width conversions */ +#ifndef KIT_INTTYPES_H +#define KIT_INTTYPES_H + +#include <stdint.h> + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +intmax_t imaxabs(intmax_t j); +imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom); +intmax_t strtoimax(const char* restrict nptr, char** restrict endptr, int base); +uintmax_t strtoumax(const char* restrict nptr, char** restrict endptr, + int base); + +#if __SIZEOF_LONG__ == 8 +#define __KIT_PRI64 "l" +#define __KIT_SCN64 "l" +#define __KIT_PRIMAX "l" +#define __KIT_SCNMAX "l" +#else +#define __KIT_PRI64 "ll" +#define __KIT_SCN64 "ll" +#define __KIT_PRIMAX "ll" +#define __KIT_SCNMAX "ll" +#endif + +#if __SIZEOF_POINTER__ == __SIZEOF_LONG__ +#define __KIT_PRIPTR "l" +#define __KIT_SCNPTR "l" +#else +#define __KIT_PRIPTR "ll" +#define __KIT_SCNPTR "ll" +#endif + +#if __SIZEOF_POINTER__ == 8 +#define __KIT_PRIFAST16 __KIT_PRI64 +#define __KIT_PRIFAST32 __KIT_PRI64 +#define __KIT_SCNFAST16 __KIT_SCN64 +#define __KIT_SCNFAST32 __KIT_SCN64 +#else +#define __KIT_PRIFAST16 "" +#define __KIT_PRIFAST32 "" +#define __KIT_SCNFAST16 "" +#define __KIT_SCNFAST32 "" +#endif + +#define PRId8 "d" +#define PRIi8 "i" +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRId16 "d" +#define PRIi16 "i" +#define PRIo16 "o" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" +#define PRId32 "d" +#define PRIi32 "i" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define PRId64 __KIT_PRI64 "d" +#define PRIi64 __KIT_PRI64 "i" +#define PRIo64 __KIT_PRI64 "o" +#define PRIu64 __KIT_PRI64 "u" +#define PRIx64 __KIT_PRI64 "x" +#define PRIX64 __KIT_PRI64 "X" + +#define PRIdLEAST8 PRId8 +#define PRIiLEAST8 PRIi8 +#define PRIoLEAST8 PRIo8 +#define PRIuLEAST8 PRIu8 +#define PRIxLEAST8 PRIx8 +#define PRIXLEAST8 PRIX8 +#define PRIdLEAST16 PRId16 +#define PRIiLEAST16 PRIi16 +#define PRIoLEAST16 PRIo16 +#define PRIuLEAST16 PRIu16 +#define PRIxLEAST16 PRIx16 +#define PRIXLEAST16 PRIX16 +#define PRIdLEAST32 PRId32 +#define PRIiLEAST32 PRIi32 +#define PRIoLEAST32 PRIo32 +#define PRIuLEAST32 PRIu32 +#define PRIxLEAST32 PRIx32 +#define PRIXLEAST32 PRIX32 +#define PRIdLEAST64 PRId64 +#define PRIiLEAST64 PRIi64 +#define PRIoLEAST64 PRIo64 +#define PRIuLEAST64 PRIu64 +#define PRIxLEAST64 PRIx64 +#define PRIXLEAST64 PRIX64 + +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" +#define PRIdFAST16 __KIT_PRIFAST16 "d" +#define PRIiFAST16 __KIT_PRIFAST16 "i" +#define PRIoFAST16 __KIT_PRIFAST16 "o" +#define PRIuFAST16 __KIT_PRIFAST16 "u" +#define PRIxFAST16 __KIT_PRIFAST16 "x" +#define PRIXFAST16 __KIT_PRIFAST16 "X" +#define PRIdFAST32 __KIT_PRIFAST32 "d" +#define PRIiFAST32 __KIT_PRIFAST32 "i" +#define PRIoFAST32 __KIT_PRIFAST32 "o" +#define PRIuFAST32 __KIT_PRIFAST32 "u" +#define PRIxFAST32 __KIT_PRIFAST32 "x" +#define PRIXFAST32 __KIT_PRIFAST32 "X" +#define PRIdFAST64 PRId64 +#define PRIiFAST64 PRIi64 +#define PRIoFAST64 PRIo64 +#define PRIuFAST64 PRIu64 +#define PRIxFAST64 PRIx64 +#define PRIXFAST64 PRIX64 + +#define PRIdMAX __KIT_PRIMAX "d" +#define PRIiMAX __KIT_PRIMAX "i" +#define PRIoMAX __KIT_PRIMAX "o" +#define PRIuMAX __KIT_PRIMAX "u" +#define PRIxMAX __KIT_PRIMAX "x" +#define PRIXMAX __KIT_PRIMAX "X" + +#define PRIdPTR __KIT_PRIPTR "d" +#define PRIiPTR __KIT_PRIPTR "i" +#define PRIoPTR __KIT_PRIPTR "o" +#define PRIuPTR __KIT_PRIPTR "u" +#define PRIxPTR __KIT_PRIPTR "x" +#define PRIXPTR __KIT_PRIPTR "X" + +#define SCNd8 "hhd" +#define SCNi8 "hhi" +#define SCNo8 "hho" +#define SCNu8 "hhu" +#define SCNx8 "hhx" +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNd32 "d" +#define SCNi32 "i" +#define SCNo32 "o" +#define SCNu32 "u" +#define SCNx32 "x" +#define SCNd64 __KIT_SCN64 "d" +#define SCNi64 __KIT_SCN64 "i" +#define SCNo64 __KIT_SCN64 "o" +#define SCNu64 __KIT_SCN64 "u" +#define SCNx64 __KIT_SCN64 "x" + +#define SCNdLEAST8 SCNd8 +#define SCNiLEAST8 SCNi8 +#define SCNoLEAST8 SCNo8 +#define SCNuLEAST8 SCNu8 +#define SCNxLEAST8 SCNx8 +#define SCNdLEAST16 SCNd16 +#define SCNiLEAST16 SCNi16 +#define SCNoLEAST16 SCNo16 +#define SCNuLEAST16 SCNu16 +#define SCNxLEAST16 SCNx16 +#define SCNdLEAST32 SCNd32 +#define SCNiLEAST32 SCNi32 +#define SCNoLEAST32 SCNo32 +#define SCNuLEAST32 SCNu32 +#define SCNxLEAST32 SCNx32 +#define SCNdLEAST64 SCNd64 +#define SCNiLEAST64 SCNi64 +#define SCNoLEAST64 SCNo64 +#define SCNuLEAST64 SCNu64 +#define SCNxLEAST64 SCNx64 + +#define SCNdFAST8 SCNd8 +#define SCNiFAST8 SCNi8 +#define SCNoFAST8 SCNo8 +#define SCNuFAST8 SCNu8 +#define SCNxFAST8 SCNx8 +#define SCNdFAST16 __KIT_SCNFAST16 "d" +#define SCNiFAST16 __KIT_SCNFAST16 "i" +#define SCNoFAST16 __KIT_SCNFAST16 "o" +#define SCNuFAST16 __KIT_SCNFAST16 "u" +#define SCNxFAST16 __KIT_SCNFAST16 "x" +#define SCNdFAST32 __KIT_SCNFAST32 "d" +#define SCNiFAST32 __KIT_SCNFAST32 "i" +#define SCNoFAST32 __KIT_SCNFAST32 "o" +#define SCNuFAST32 __KIT_SCNFAST32 "u" +#define SCNxFAST32 __KIT_SCNFAST32 "x" +#define SCNdFAST64 SCNd64 +#define SCNiFAST64 SCNi64 +#define SCNoFAST64 SCNo64 +#define SCNuFAST64 SCNu64 +#define SCNxFAST64 SCNx64 + +#define SCNdMAX __KIT_SCNMAX "d" +#define SCNiMAX __KIT_SCNMAX "i" +#define SCNoMAX __KIT_SCNMAX "o" +#define SCNuMAX __KIT_SCNMAX "u" +#define SCNxMAX __KIT_SCNMAX "x" + +#define SCNdPTR __KIT_SCNPTR "d" +#define SCNiPTR __KIT_SCNPTR "i" +#define SCNoPTR __KIT_SCNPTR "o" +#define SCNuPTR __KIT_SCNPTR "u" +#define SCNxPTR __KIT_SCNPTR "x" + +#define __STDC_VERSION_INTTYPES_H__ 202311L + +#endif diff --git a/rt/include/limits.h b/rt/include/limits.h @@ -14,6 +14,18 @@ #define KIT_LIMITS_H #define CHAR_BIT 8 +#define BOOL_WIDTH 1 +#define CHAR_WIDTH 8 +#define SCHAR_WIDTH 8 +#define UCHAR_WIDTH 8 +#define SHRT_WIDTH 16 +#define USHRT_WIDTH 16 +#define INT_WIDTH 32 +#define UINT_WIDTH 32 +#define LONG_WIDTH (__SIZEOF_LONG__ * CHAR_BIT) +#define ULONG_WIDTH (__SIZEOF_LONG__ * CHAR_BIT) +#define LLONG_WIDTH 64 +#define ULLONG_WIDTH 64 #define MB_LEN_MAX 1 /* freestanding has no locale; smallest legal value */ /* signed / unsigned char */ diff --git a/rt/include/stdbit.h b/rt/include/stdbit.h @@ -0,0 +1,417 @@ +/* stdbit.h -- C23 7.18a -- Bit and byte utilities */ +#ifndef KIT_STDBIT_H +#define KIT_STDBIT_H + +#include <stdbool.h> +#include <limits.h> + +#define __STDC_VERSION_STDBIT_H__ 202311L + +#define __STDC_ENDIAN_LITTLE__ 1234 +#define __STDC_ENDIAN_BIG__ 4321 +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__ +#else +#define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ +#endif + +#define __KIT_STDBIT_WIDTH(T) ((unsigned)(sizeof(T) * CHAR_BIT)) + +static inline unsigned int stdc_leading_zeros_uc(unsigned char v) { + unsigned int w = __KIT_STDBIT_WIDTH(unsigned char); + if (v == 0) return w; + return (unsigned int)__builtin_clz((unsigned int)v) - + (__KIT_STDBIT_WIDTH(unsigned int) - w); +} + +static inline unsigned int stdc_leading_zeros_us(unsigned short v) { + unsigned int w = __KIT_STDBIT_WIDTH(unsigned short); + if (v == 0) return w; + return (unsigned int)__builtin_clz((unsigned int)v) - + (__KIT_STDBIT_WIDTH(unsigned int) - w); +} + +static inline unsigned int stdc_leading_zeros_ui(unsigned int v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned int); + return (unsigned int)__builtin_clz(v); +} + +static inline unsigned int stdc_leading_zeros_ul(unsigned long v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned long); +#if __SIZEOF_LONG__ == 8 + return (unsigned int)__builtin_clzll((unsigned long long)v); +#else + return (unsigned int)__builtin_clz((unsigned int)v); +#endif +} + +static inline unsigned int stdc_leading_zeros_ull(unsigned long long v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned long long); + return (unsigned int)__builtin_clzll(v); +} + +static inline unsigned int stdc_trailing_zeros_uc(unsigned char v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned char); + return (unsigned int)__builtin_ctz((unsigned int)v); +} + +static inline unsigned int stdc_trailing_zeros_us(unsigned short v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned short); + return (unsigned int)__builtin_ctz((unsigned int)v); +} + +static inline unsigned int stdc_trailing_zeros_ui(unsigned int v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned int); + return (unsigned int)__builtin_ctz(v); +} + +static inline unsigned int stdc_trailing_zeros_ul(unsigned long v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned long); +#if __SIZEOF_LONG__ == 8 + return (unsigned int)__builtin_ctzll((unsigned long long)v); +#else + return (unsigned int)__builtin_ctz((unsigned int)v); +#endif +} + +static inline unsigned int stdc_trailing_zeros_ull(unsigned long long v) { + if (v == 0) return __KIT_STDBIT_WIDTH(unsigned long long); + return (unsigned int)__builtin_ctzll(v); +} + +static inline unsigned int stdc_count_ones_uc(unsigned char v) { + unsigned int n = 0; + while (v != 0) { + n += (unsigned int)(v & 1u); + v = (unsigned char)(v >> 1u); + } + return n; +} + +static inline unsigned int stdc_count_ones_us(unsigned short v) { + unsigned int n = 0; + while (v != 0) { + n += (unsigned int)(v & 1u); + v = (unsigned short)(v >> 1u); + } + return n; +} + +static inline unsigned int stdc_count_ones_ui(unsigned int v) { + unsigned int n = 0; + while (v != 0) { + n += v & 1u; + v >>= 1u; + } + return n; +} + +static inline unsigned int stdc_count_ones_ul(unsigned long v) { + unsigned int n = 0; + while (v != 0) { + n += (unsigned int)(v & 1ul); + v >>= 1u; + } + return n; +} + +static inline unsigned int stdc_count_ones_ull(unsigned long long v) { + unsigned int n = 0; + while (v != 0) { + n += (unsigned int)(v & 1ull); + v >>= 1u; + } + return n; +} + +static inline unsigned int stdc_leading_ones_uc(unsigned char v) { + return stdc_leading_zeros_uc((unsigned char)~v); +} +static inline unsigned int stdc_leading_ones_us(unsigned short v) { + return stdc_leading_zeros_us((unsigned short)~v); +} +static inline unsigned int stdc_leading_ones_ui(unsigned int v) { + return stdc_leading_zeros_ui(~v); +} +static inline unsigned int stdc_leading_ones_ul(unsigned long v) { + return stdc_leading_zeros_ul(~v); +} +static inline unsigned int stdc_leading_ones_ull(unsigned long long v) { + return stdc_leading_zeros_ull(~v); +} + +static inline unsigned int stdc_trailing_ones_uc(unsigned char v) { + return stdc_trailing_zeros_uc((unsigned char)~v); +} +static inline unsigned int stdc_trailing_ones_us(unsigned short v) { + return stdc_trailing_zeros_us((unsigned short)~v); +} +static inline unsigned int stdc_trailing_ones_ui(unsigned int v) { + return stdc_trailing_zeros_ui(~v); +} +static inline unsigned int stdc_trailing_ones_ul(unsigned long v) { + return stdc_trailing_zeros_ul(~v); +} +static inline unsigned int stdc_trailing_ones_ull(unsigned long long v) { + return stdc_trailing_zeros_ull(~v); +} + +static inline unsigned int stdc_count_zeros_uc(unsigned char v) { + return __KIT_STDBIT_WIDTH(unsigned char) - stdc_count_ones_uc(v); +} +static inline unsigned int stdc_count_zeros_us(unsigned short v) { + return __KIT_STDBIT_WIDTH(unsigned short) - stdc_count_ones_us(v); +} +static inline unsigned int stdc_count_zeros_ui(unsigned int v) { + return __KIT_STDBIT_WIDTH(unsigned int) - stdc_count_ones_ui(v); +} +static inline unsigned int stdc_count_zeros_ul(unsigned long v) { + return __KIT_STDBIT_WIDTH(unsigned long) - stdc_count_ones_ul(v); +} +static inline unsigned int stdc_count_zeros_ull(unsigned long long v) { + return __KIT_STDBIT_WIDTH(unsigned long long) - stdc_count_ones_ull(v); +} + +static inline bool stdc_has_single_bit_uc(unsigned char v) { + return v != 0 && (unsigned char)(v & (unsigned char)(v - 1u)) == 0; +} +static inline bool stdc_has_single_bit_us(unsigned short v) { + return v != 0 && (unsigned short)(v & (unsigned short)(v - 1u)) == 0; +} +static inline bool stdc_has_single_bit_ui(unsigned int v) { + return v != 0 && (v & (v - 1u)) == 0; +} +static inline bool stdc_has_single_bit_ul(unsigned long v) { + return v != 0 && (v & (v - 1ul)) == 0; +} +static inline bool stdc_has_single_bit_ull(unsigned long long v) { + return v != 0 && (v & (v - 1ull)) == 0; +} + +static inline unsigned int stdc_bit_width_uc(unsigned char v) { + return __KIT_STDBIT_WIDTH(unsigned char) - stdc_leading_zeros_uc(v); +} +static inline unsigned int stdc_bit_width_us(unsigned short v) { + return __KIT_STDBIT_WIDTH(unsigned short) - stdc_leading_zeros_us(v); +} +static inline unsigned int stdc_bit_width_ui(unsigned int v) { + return __KIT_STDBIT_WIDTH(unsigned int) - stdc_leading_zeros_ui(v); +} +static inline unsigned int stdc_bit_width_ul(unsigned long v) { + return __KIT_STDBIT_WIDTH(unsigned long) - stdc_leading_zeros_ul(v); +} +static inline unsigned int stdc_bit_width_ull(unsigned long long v) { + return __KIT_STDBIT_WIDTH(unsigned long long) - stdc_leading_zeros_ull(v); +} + +static inline unsigned char stdc_bit_floor_uc(unsigned char v) { + return v == 0 ? 0 : (unsigned char)(1u << (stdc_bit_width_uc(v) - 1u)); +} +static inline unsigned short stdc_bit_floor_us(unsigned short v) { + return v == 0 ? 0 : (unsigned short)(1u << (stdc_bit_width_us(v) - 1u)); +} +static inline unsigned int stdc_bit_floor_ui(unsigned int v) { + return v == 0 ? 0 : (1u << (stdc_bit_width_ui(v) - 1u)); +} +static inline unsigned long stdc_bit_floor_ul(unsigned long v) { + return v == 0 ? 0 : (1ul << (stdc_bit_width_ul(v) - 1u)); +} +static inline unsigned long long stdc_bit_floor_ull(unsigned long long v) { + return v == 0 ? 0 : (1ull << (stdc_bit_width_ull(v) - 1u)); +} + +static inline unsigned char stdc_bit_ceil_uc(unsigned char v) { + unsigned int w; + if (v <= 1u) return 1u; + w = stdc_bit_width_uc((unsigned char)(v - 1u)); + return w >= __KIT_STDBIT_WIDTH(unsigned char) ? 0 : (unsigned char)(1u << w); +} +static inline unsigned short stdc_bit_ceil_us(unsigned short v) { + unsigned int w; + if (v <= 1u) return 1u; + w = stdc_bit_width_us((unsigned short)(v - 1u)); + return w >= __KIT_STDBIT_WIDTH(unsigned short) ? 0 + : (unsigned short)(1u << w); +} +static inline unsigned int stdc_bit_ceil_ui(unsigned int v) { + unsigned int w; + if (v <= 1u) return 1u; + w = stdc_bit_width_ui(v - 1u); + return w >= __KIT_STDBIT_WIDTH(unsigned int) ? 0 : (1u << w); +} +static inline unsigned long stdc_bit_ceil_ul(unsigned long v) { + unsigned int w; + if (v <= 1ul) return 1ul; + w = stdc_bit_width_ul(v - 1ul); + return w >= __KIT_STDBIT_WIDTH(unsigned long) ? 0 : (1ul << w); +} +static inline unsigned long long stdc_bit_ceil_ull(unsigned long long v) { + unsigned int w; + if (v <= 1ull) return 1ull; + w = stdc_bit_width_ull(v - 1ull); + return w >= __KIT_STDBIT_WIDTH(unsigned long long) ? 0 : (1ull << w); +} + +static inline unsigned int stdc_first_leading_zero_uc(unsigned char v) { + return v == (unsigned char)~0u ? 0 : stdc_leading_ones_uc(v) + 1u; +} +static inline unsigned int stdc_first_leading_zero_us(unsigned short v) { + return v == (unsigned short)~0u ? 0 : stdc_leading_ones_us(v) + 1u; +} +static inline unsigned int stdc_first_leading_zero_ui(unsigned int v) { + return v == ~0u ? 0 : stdc_leading_ones_ui(v) + 1u; +} +static inline unsigned int stdc_first_leading_zero_ul(unsigned long v) { + return v == ~0ul ? 0 : stdc_leading_ones_ul(v) + 1u; +} +static inline unsigned int stdc_first_leading_zero_ull(unsigned long long v) { + return v == ~0ull ? 0 : stdc_leading_ones_ull(v) + 1u; +} + +static inline unsigned int stdc_first_leading_one_uc(unsigned char v) { + return v == 0 ? 0 : stdc_leading_zeros_uc(v) + 1u; +} +static inline unsigned int stdc_first_leading_one_us(unsigned short v) { + return v == 0 ? 0 : stdc_leading_zeros_us(v) + 1u; +} +static inline unsigned int stdc_first_leading_one_ui(unsigned int v) { + return v == 0 ? 0 : stdc_leading_zeros_ui(v) + 1u; +} +static inline unsigned int stdc_first_leading_one_ul(unsigned long v) { + return v == 0 ? 0 : stdc_leading_zeros_ul(v) + 1u; +} +static inline unsigned int stdc_first_leading_one_ull(unsigned long long v) { + return v == 0 ? 0 : stdc_leading_zeros_ull(v) + 1u; +} + +static inline unsigned int stdc_first_trailing_zero_uc(unsigned char v) { + return v == (unsigned char)~0u ? 0 : stdc_trailing_ones_uc(v) + 1u; +} +static inline unsigned int stdc_first_trailing_zero_us(unsigned short v) { + return v == (unsigned short)~0u ? 0 : stdc_trailing_ones_us(v) + 1u; +} +static inline unsigned int stdc_first_trailing_zero_ui(unsigned int v) { + return v == ~0u ? 0 : stdc_trailing_ones_ui(v) + 1u; +} +static inline unsigned int stdc_first_trailing_zero_ul(unsigned long v) { + return v == ~0ul ? 0 : stdc_trailing_ones_ul(v) + 1u; +} +static inline unsigned int stdc_first_trailing_zero_ull(unsigned long long v) { + return v == ~0ull ? 0 : stdc_trailing_ones_ull(v) + 1u; +} + +static inline unsigned int stdc_first_trailing_one_uc(unsigned char v) { + return v == 0 ? 0 : stdc_trailing_zeros_uc(v) + 1u; +} +static inline unsigned int stdc_first_trailing_one_us(unsigned short v) { + return v == 0 ? 0 : stdc_trailing_zeros_us(v) + 1u; +} +static inline unsigned int stdc_first_trailing_one_ui(unsigned int v) { + return v == 0 ? 0 : stdc_trailing_zeros_ui(v) + 1u; +} +static inline unsigned int stdc_first_trailing_one_ul(unsigned long v) { + return v == 0 ? 0 : stdc_trailing_zeros_ul(v) + 1u; +} +static inline unsigned int stdc_first_trailing_one_ull(unsigned long long v) { + return v == 0 ? 0 : stdc_trailing_zeros_ull(v) + 1u; +} + +#define __KIT_STDBIT_WIDTH_EXPR(v) ((unsigned)(sizeof(v) * CHAR_BIT)) + +static inline unsigned long long __kit_stdbit_mask(unsigned int width) { + return width >= __KIT_STDBIT_WIDTH(unsigned long long) + ? ~0ull + : ((1ull << width) - 1ull); +} + +static inline unsigned int __kit_stdbit_lz(unsigned long long v, + unsigned int width) { + v &= __kit_stdbit_mask(width); + if (v == 0) return width; + return (unsigned int)__builtin_clzll(v) - + (__KIT_STDBIT_WIDTH(unsigned long long) - width); +} + +static inline unsigned int __kit_stdbit_tz(unsigned long long v, + unsigned int width) { + v &= __kit_stdbit_mask(width); + if (v == 0) return width; + return (unsigned int)__builtin_ctzll(v); +} + +static inline unsigned int __kit_stdbit_pop(unsigned long long v, + unsigned int width) { + unsigned int n = 0; + v &= __kit_stdbit_mask(width); + while (v != 0) { + n += (unsigned int)(v & 1ull); + v >>= 1u; + } + return n; +} + +static inline unsigned long long __kit_stdbit_floor(unsigned long long v, + unsigned int width) { + unsigned int w; + v &= __kit_stdbit_mask(width); + if (v == 0) return 0; + w = width - __kit_stdbit_lz(v, width) - 1u; + return 1ull << w; +} + +static inline unsigned long long __kit_stdbit_ceil(unsigned long long v, + unsigned int width) { + unsigned int w; + v &= __kit_stdbit_mask(width); + if (v <= 1ull) return 1ull; + w = width - __kit_stdbit_lz(v - 1ull, width); + return w >= width ? 0ull : (1ull << w); +} + +static inline bool __kit_stdbit_single(unsigned long long v, + unsigned int width) { + v &= __kit_stdbit_mask(width); + return v != 0 && (v & (v - 1ull)) == 0; +} + +static inline unsigned int __kit_stdbit_first_lz(unsigned long long v, + unsigned int width) { + unsigned int n = __kit_stdbit_lz(v, width); + return n == width ? 0u : n + 1u; +} + +static inline unsigned int __kit_stdbit_first_tz(unsigned long long v, + unsigned int width) { + unsigned int n = __kit_stdbit_tz(v, width); + return n == width ? 0u : n + 1u; +} + +#define stdc_leading_zeros(v) \ + __kit_stdbit_lz((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_leading_ones(v) \ + __kit_stdbit_lz(~(unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_trailing_zeros(v) \ + __kit_stdbit_tz((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_trailing_ones(v) \ + __kit_stdbit_tz(~(unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_first_leading_zero(v) \ + __kit_stdbit_first_lz(~(unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_first_leading_one(v) \ + __kit_stdbit_first_lz((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_first_trailing_zero(v) \ + __kit_stdbit_first_tz(~(unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_first_trailing_one(v) \ + __kit_stdbit_first_tz((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_count_ones(v) \ + __kit_stdbit_pop((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_count_zeros(v) (__KIT_STDBIT_WIDTH_EXPR(v) - stdc_count_ones(v)) +#define stdc_has_single_bit(v) \ + __kit_stdbit_single((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_bit_width(v) \ + (__KIT_STDBIT_WIDTH_EXPR(v) - stdc_leading_zeros(v)) +#define stdc_bit_floor(v) \ + __kit_stdbit_floor((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) +#define stdc_bit_ceil(v) \ + __kit_stdbit_ceil((unsigned long long)(v), __KIT_STDBIT_WIDTH_EXPR(v)) + +#endif diff --git a/rt/include/stdckdint.h b/rt/include/stdckdint.h @@ -0,0 +1,13 @@ +/* stdckdint.h -- C23 7.20 -- Checked integer arithmetic */ +#ifndef KIT_STDCKDINT_H +#define KIT_STDCKDINT_H + +#include <stdbool.h> + +#define __STDC_VERSION_STDCKDINT_H__ 202311L + +#define ckd_add(result, a, b) __builtin_add_overflow((a), (b), (result)) +#define ckd_sub(result, a, b) __builtin_sub_overflow((a), (b), (result)) +#define ckd_mul(result, a, b) __builtin_mul_overflow((a), (b), (result)) + +#endif diff --git a/rt/include/stddef.h b/rt/include/stddef.h @@ -19,5 +19,8 @@ typedef struct { #define NULL ((void*)0) #define offsetof(type, member) __builtin_offsetof(type, member) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +#define unreachable() __builtin_unreachable() +#endif #endif diff --git a/rt/include/stdint.h b/rt/include/stdint.h @@ -140,6 +140,49 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ #define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ +#define INT8_WIDTH 8 +#define INT16_WIDTH 16 +#define INT32_WIDTH 32 +#define INT64_WIDTH 64 +#define UINT8_WIDTH 8 +#define UINT16_WIDTH 16 +#define UINT32_WIDTH 32 +#define UINT64_WIDTH 64 +#define INT_LEAST8_WIDTH 8 +#define INT_LEAST16_WIDTH 16 +#define INT_LEAST32_WIDTH 32 +#define INT_LEAST64_WIDTH 64 +#define UINT_LEAST8_WIDTH 8 +#define UINT_LEAST16_WIDTH 16 +#define UINT_LEAST32_WIDTH 32 +#define UINT_LEAST64_WIDTH 64 +#define INT_FAST8_WIDTH 8 +#define UINT_FAST8_WIDTH 8 +#if __SIZEOF_POINTER__ == 8 +#define INT_FAST16_WIDTH 64 +#define INT_FAST32_WIDTH 64 +#define INT_FAST64_WIDTH 64 +#define UINT_FAST16_WIDTH 64 +#define UINT_FAST32_WIDTH 64 +#define UINT_FAST64_WIDTH 64 +#else +#define INT_FAST16_WIDTH 32 +#define INT_FAST32_WIDTH 32 +#define INT_FAST64_WIDTH 64 +#define UINT_FAST16_WIDTH 32 +#define UINT_FAST32_WIDTH 32 +#define UINT_FAST64_WIDTH 64 +#endif +#define INTPTR_WIDTH (__SIZEOF_POINTER__ * 8) +#define UINTPTR_WIDTH (__SIZEOF_POINTER__ * 8) +#define INTMAX_WIDTH 64 +#define UINTMAX_WIDTH 64 +#define PTRDIFF_WIDTH (__SIZEOF_PTRDIFF_T__ * 8) +#define SIZE_WIDTH (__SIZEOF_SIZE_T__ * 8) +#define WCHAR_WIDTH (__SIZEOF_WCHAR_T__ * 8) +#define WINT_WIDTH (__SIZEOF_WINT_T__ * 8) +#define SIG_ATOMIC_WIDTH 32 + /* ------------------------------------------------------------------ */ /* 7.20.4 Macros for integer constants */ /* ------------------------------------------------------------------ */ diff --git a/rt/include/stdlib.h b/rt/include/stdlib.h @@ -31,6 +31,7 @@ long strtol(const char* nptr, char** endptr, int base); long long strtoll(const char* nptr, char** endptr, int base); unsigned long strtoul(const char* nptr, char** endptr, int base); unsigned long long strtoull(const char* nptr, char** endptr, int base); +size_t memalignment(const void* p); int abs(int j); long labs(long j); diff --git a/rt/include/string.h b/rt/include/string.h @@ -7,8 +7,10 @@ void* memcpy(void* dest, const void* src, size_t n); void* memmove(void* dest, const void* src, size_t n); void* memset(void* s, int c, size_t n); +void* memset_explicit(void* s, int c, size_t n); int memcmp(const void* s1, const void* s2, size_t n); void* memchr(const void* s, int c, size_t n); +void* memccpy(void* dest, const void* src, int c, size_t n); char* strcpy(char* dest, const char* src); char* strncpy(char* dest, const char* src, size_t n); @@ -18,8 +20,13 @@ int strcmp(const char* s1, const char* s2); int strncmp(const char* s1, const char* s2, size_t n); char* strchr(const char* s, int c); char* strrchr(const char* s, int c); +size_t strspn(const char* s, const char* accept); +size_t strcspn(const char* s, const char* reject); +char* strpbrk(const char* s, const char* accept); char* strstr(const char* haystack, const char* needle); size_t strlen(const char* s); size_t strnlen(const char* s, size_t maxlen); +#define __STDC_VERSION_STRING_H__ 202311L + #endif diff --git a/rt/lib/mem/mem.c b/rt/lib/mem/mem.c @@ -36,6 +36,13 @@ __attribute__((weak)) void* memset(void* dst, int c, size_t n) { return dst; } +__attribute__((weak)) void* memset_explicit(void* dst, int c, size_t n) { + volatile unsigned char* d = (volatile unsigned char*)dst; + unsigned char v = (unsigned char)c; + for (size_t i = 0; i < n; i++) d[i] = v; + return dst; +} + __attribute__((weak)) int memcmp(const void* a, const void* b, size_t n) { const unsigned char* p = (const unsigned char*)a; const unsigned char* q = (const unsigned char*)b; diff --git a/rt/lib/stdlib/stdlib.c b/rt/lib/stdlib/stdlib.c @@ -178,6 +178,42 @@ __attribute__((weak)) float strtof(const char* nptr, char** endptr) { return (float)kit_strtold_impl(nptr, endptr); } +__attribute__((weak)) size_t memalignment(const void* p) { + __UINTPTR_TYPE__ v = (__UINTPTR_TYPE__)p; + if (v == 0) return 0; + return (size_t)(v & (0u - v)); +} + +typedef __INTMAX_TYPE__ kit_intmax_t; +typedef __UINTMAX_TYPE__ kit_uintmax_t; + +typedef struct { + kit_intmax_t quot; + kit_intmax_t rem; +} imaxdiv_t; + +__attribute__((weak)) kit_intmax_t imaxabs(kit_intmax_t j) { + return j < 0 ? -j : j; +} + +__attribute__((weak)) imaxdiv_t imaxdiv(kit_intmax_t numer, + kit_intmax_t denom) { + imaxdiv_t r; + r.quot = numer / denom; + r.rem = numer % denom; + return r; +} + +__attribute__((weak)) kit_intmax_t strtoimax(const char* nptr, char** endptr, + int base) { + return (kit_intmax_t)strtoll(nptr, endptr, base); +} + +__attribute__((weak)) kit_uintmax_t strtoumax(const char* nptr, char** endptr, + int base) { + return (kit_uintmax_t)strtoull(nptr, endptr, base); +} + __attribute__((weak)) int abs(int j) { return j < 0 ? -j : j; } __attribute__((weak)) long labs(long j) { return j < 0 ? -j : j; } __attribute__((weak)) long long llabs(long long j) { return j < 0 ? -j : j; } diff --git a/rt/lib/string/string.c b/rt/lib/string/string.c @@ -14,6 +14,18 @@ __attribute__((weak)) void* memchr(const void* s, int c, size_t n) { return NULL; } +__attribute__((weak)) void* memccpy(void* dest, const void* src, int c, + size_t n) { + unsigned char* d = (unsigned char*)dest; + const unsigned char* s = (const unsigned char*)src; + unsigned char v = (unsigned char)c; + for (size_t i = 0; i < n; i++) { + d[i] = s[i]; + if (s[i] == v) return d + i + 1u; + } + return NULL; +} + __attribute__((weak)) size_t strlen(const char* s) { size_t n = 0; while (s[n] != '\0') n++; @@ -94,6 +106,34 @@ __attribute__((weak)) char* strrchr(const char* s, int c) { } } +static int kit_str_contains(const char* s, char c) { + while (*s != '\0') { + if (*s == c) return 1; + s++; + } + return 0; +} + +__attribute__((weak)) size_t strspn(const char* s, const char* accept) { + size_t n = 0; + while (s[n] != '\0' && kit_str_contains(accept, s[n])) n++; + return n; +} + +__attribute__((weak)) size_t strcspn(const char* s, const char* reject) { + size_t n = 0; + while (s[n] != '\0' && !kit_str_contains(reject, s[n])) n++; + return n; +} + +__attribute__((weak)) char* strpbrk(const char* s, const char* accept) { + while (*s != '\0') { + if (kit_str_contains(accept, *s)) return (char*)s; + s++; + } + return NULL; +} + __attribute__((weak)) char* strstr(const char* haystack, const char* needle) { if (*needle == '\0') return (char*)haystack; for (; *haystack != '\0'; haystack++) { diff --git a/test/rt/cases/freestanding_lib.c b/test/rt/cases/freestanding_lib.c @@ -1,6 +1,11 @@ #include <assert.h> +#include <inttypes.h> +#include <limits.h> #include <stdarg.h> +#include <stdbool.h> #include <stddef.h> +#include <stdbit.h> +#include <stdckdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -63,10 +68,19 @@ static int strings_ok(void) { if (strnlen(buf, 4) != 4) return 0; if (strchr(buf, ' ') != buf + 5) return 0; if (strrchr(buf, 'a') != buf + 9) return 0; + if (strspn(buf, "alph ") != 6) return 0; + if (strcspn(buf, "tb") != 6) return 0; + if (strpbrk(buf, "tb") != buf + 6) return 0; if (strstr(buf, "ha be") != buf + 3) return 0; strncpy(small, "xy", sizeof(small)); if (small[0] != 'x' || small[1] != 'y' || small[2] != '\0') return 0; + + memset(small, '?', sizeof(small)); + if (memccpy(small, "abcd", 'c', 4) != small + 3) return 0; + if (memcmp(small, "abc?", 4) != 0) return 0; + memset_explicit(small, 0, sizeof(small)); + if (small[0] != '\0' || small[sizeof(small) - 1] != '\0') return 0; return 1; } @@ -78,6 +92,8 @@ static int stdlib_ok(void) { div_t d; ldiv_t ld; lldiv_t lld; + imaxdiv_t imd; + char aligned[32]; if (atoi(" -42x") != -42) return 0; if (atol("123") != 123L) return 0; @@ -89,14 +105,27 @@ static int stdlib_ok(void) { if ((int)(strtod("12.5e1z", &end) + 0.5) != 125 || *end != 'z') return 0; if ((int)(strtof("4.25", &end) * 4.0f) != 17 || *end != '\0') return 0; if ((int)strtold("9.0", &end) != 9 || *end != '\0') return 0; + if (strtoimax("-9223372036854775807", &end, 10) != + (intmax_t)-9223372036854775807LL || + *end != '\0') + return 0; + if (strtoumax("18446744073709551615", &end, 10) != + (uintmax_t)18446744073709551615ULL || + *end != '\0') + return 0; if (abs(-7) != 7 || labs(-8L) != 8L || llabs(-9LL) != 9LL) return 0; + if (imaxabs((intmax_t)-10) != (intmax_t)10) return 0; d = div(17, 5); ld = ldiv(17L, 5L); lld = lldiv(17LL, 5LL); + imd = imaxdiv((intmax_t)17, (intmax_t)5); if (d.quot != 3 || d.rem != 2) return 0; if (ld.quot != 3 || ld.rem != 2) return 0; if (lld.quot != 3 || lld.rem != 2) return 0; + if (imd.quot != 3 || imd.rem != 2) return 0; + if (memalignment(NULL) != 0) return 0; + if (memalignment(aligned) < 1) return 0; qsort(values, 6, sizeof(values[0]), cmp_int); for (int i = 0; i < 6; i++) { @@ -107,6 +136,37 @@ static int stdlib_ok(void) { return 1; } +static int c23_bits_ok(void) { + int out; + + if (CHAR_WIDTH != 8 || INT_WIDTH != 32 || INT64_WIDTH != 64) return 0; + if (stdc_leading_zeros_uc((unsigned char)0x10u) != 3) return 0; + if (stdc_trailing_zeros_ui(0x20u) != 5) return 0; + if (stdc_count_ones_ui(0xb1u) != 4) return 0; + if (stdc_count_zeros_uc((unsigned char)0xf0u) != 4) return 0; + if (!stdc_has_single_bit_ui(0x8000u)) return 0; + if (stdc_has_single_bit_ui(0x8001u)) return 0; + if (stdc_bit_width_ui(0x80u) != 8) return 0; + if (stdc_bit_floor_ui(130u) != 128u) return 0; + if (stdc_bit_ceil_ui(129u) != 256u) return 0; + if (stdc_first_leading_one_uc((unsigned char)0x10u) != 4) return 0; + if (stdc_first_trailing_one_ui(0x10u) != 5) return 0; + if (stdc_first_leading_zero_uc((unsigned char)0xefu) != 4) return 0; + if (stdc_first_trailing_zero_ui(0xefu) != 5) return 0; + if (stdc_leading_ones((unsigned char)0xf0u) != 4) return 0; + if (stdc_trailing_ones((unsigned int)0x0fu) != 4) return 0; + if (stdc_count_zeros((unsigned char)0xf0u) != 4) return 0; + if (stdc_bit_width((unsigned int)0x80u) != 8) return 0; + if (stdc_bit_floor((unsigned int)130u) != 128u) return 0; + if (stdc_bit_ceil((unsigned int)129u) != 256u) return 0; + + if (ckd_add(&out, INT_MAX, 1) != true) return 0; + if (ckd_add(&out, 10, 20) != false || out != 30) return 0; + if (ckd_sub(&out, INT_MIN, 1) != true) return 0; + if (ckd_mul(&out, 7, 6) != false || out != 42) return 0; + return 1; +} + static int stdio_ok(void) { char buf[64]; int rc; @@ -114,6 +174,10 @@ static int stdio_ok(void) { rc = snprintf(buf, sizeof(buf), "%s:%d:%04x:%c", "id", -7, 26, '!'); if (rc != 12 || strcmp(buf, "id:-7:001a:!") != 0) return 31; + rc = snprintf(buf, sizeof(buf), "%" PRIdMAX "/%" PRIuMAX, (intmax_t)-9, + (uintmax_t)10); + if (rc != 5 || strcmp(buf, "-9/10") != 0) return 30; + rc = snprintf(buf, 6, "abcdef"); if (rc != 6 || strcmp(buf, "abcde") != 0) return 32; @@ -162,6 +226,7 @@ int test_main(void) { assert(1); if (!strings_ok()) return 1; if (!stdlib_ok()) return 2; + if (!c23_bits_ok()) return 3; rc = stdio_ok(); if (rc != 0) return rc; return 42; diff --git a/test/rt/smoke.c b/test/rt/smoke.c @@ -28,6 +28,7 @@ #include <ctype.h> #include <float.h> +#include <inttypes.h> #include <iso646.h> #include <kit/backtrace.h> #include <kit/coro.h> @@ -36,7 +37,9 @@ #include <stdalign.h> #include <stdarg.h> #include <stdatomic.h> +#include <stdbit.h> #include <stdbool.h> +#include <stdckdint.h> #include <stddef.h> #include <stdint.h> #include <stdnoreturn.h> @@ -88,6 +91,13 @@ _Static_assert(sizeof(intmax_t) >= sizeof(long long), "intmax >= long long"); _Static_assert(INT32_C(1) + INT32_C(2) == 3, "INT_C macros work"); _Static_assert(UINT64_C(0xFFFFFFFFFFFFFFFF) == UINT64_MAX, "UINT64_C"); +_Static_assert(INT_WIDTH == 32, "C23 width macro"); +_Static_assert(UINTPTR_WIDTH == sizeof(uintptr_t) * CHAR_BIT, "uintptr width"); +_Static_assert(__STDC_VERSION_INTTYPES_H__ == 202311L, "inttypes version"); +_Static_assert(__STDC_VERSION_STDBIT_H__ == 202311L, "stdbit version"); +_Static_assert(__STDC_VERSION_STDCKDINT_H__ == 202311L, "stdckdint version"); +_Static_assert(__STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_LITTLE__, + "kit targets little-endian"); /* iso646 substitutions */ _Static_assert((1 and 1) == 1, "and"); @@ -223,6 +233,23 @@ static int kit_ctype_compiles(void) { tolower('Z') == 'z' && toupper('z') == 'Z'; } +static int kit_c23_headers_compile(void) { + int checked; + imaxdiv_t d = imaxdiv((intmax_t)17, (intmax_t)5); + if (imaxabs((intmax_t)-3) != (intmax_t)3) return 0; + if (d.quot != 3 || d.rem != 2) return 0; + if (strtoimax("7", (char**)0, 10) != (intmax_t)7) return 0; + if (strtoumax("10", (char**)0, 10) != (uintmax_t)10) return 0; + if (stdc_leading_zeros_uc((unsigned char)0x10u) != 3) return 0; + if (stdc_trailing_zeros_ui(0x20u) != 5) return 0; + if (stdc_count_ones_ui(0xb1u) != 4) return 0; + if (!stdc_has_single_bit_ui(0x80u)) return 0; + if (stdc_bit_floor_ui(130u) != 128u) return 0; + if (stdc_bit_ceil_ui(129u) != 256u) return 0; + if (ckd_add(&checked, 40, 2)) return 0; + return checked == 42; +} + /* kit/backtrace: the capture/print surface compiles and resolves. Compile-only -- smoke.c never links against a libkit_rt, so the actual walk never runs. */ static int kit_backtrace_compiles(void) { @@ -240,5 +267,6 @@ int kit_smoke_ok(void) { if (0) (void)kit_coro_compiles(); if (0) (void)kit_backtrace_compiles(); if (0) (void)kit_ctype_compiles(); + if (0) (void)kit_c23_headers_compile(); return sum_n(3, 1, 2, 3) == 6 && kit_atomic_ok(); }