Index: kcore/kcore.md ================================================================== --- kcore/kcore.md +++ kcore/kcore.md @@ -3,25 +3,34 @@ ## entry when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform. ## types -kcore contains fixed-width integer types (in ). note that the availability of each depends on your platform; compilation will fail if e.g. you try to use a u64 or a u128 on a 32-bit platform, so where exact lengths are not required, you may wish to use the built-in C types instead. +kcore contains fixed-width integer types (in ``). these types are present on every platform. if a platform has a type with a given bit length, it will be used, otherwise, the type will round to the largest available type (except `u8` and `s8`). if you need to be absolutely certain that a type is the appropriate bit length, use sizeof to check its length in a conditional or static assert, for instance `if (sizeof(u16) == 16 / kc_byte_bits)`. - * `u8` - an unsigned 8-bit integer - * `s8` - a signed 8-bit integer + * `u8` - an unsigned 8-bit integer, or the smallest available unsigned type + * `s8` - a signed 8-bit integer, or the smallest available signed type * `u16` - an unsigned 16-bit integer * `s16` - a signed 16-bit integer * `u32` - an unsigned 32-bit integer * `s32` - a signed 32-bit integer * `u64` - an unsigned 64-bit integer * `s64` - a signed 64-bit integer - * `u128` - an unsigned 128-bit integer - * `s128` - a signed 128-bit integer - * `word` - an unsigned integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) - * `sword` - a signed integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) + * `u128` - an unsigned 128-bit integer (uses GCC and clang extensions to offer 128-bit integer support on x86-64) + * `s128` - a signed 128-bit integer (ibid) + * `ubig` - the largest available unsigned integer type + * `sbig` - the largest available signed integer type. note: ubig and sbig really are the *largest* possible integer types not just the largest native types - if your compiler has extensions for 128-bit types on your arch (as GCC and clang do on x86-64), ubig and sbig will be 128 bits long even if your system word length is less than 128. so only use ubig/sbig if you really, really mean it. + * `ubyte` - the smallest available unsigned integer type besides \_Bool + * `sbyte` - the smallest available signed integer type besides \_Bool * `stat` - the type of process return values expected by the platform (usually u8 on linux) + * `sz` - a type large enough to cover a platform's entire address space (libc equivalent size_t) + * `offset` - a type that can contain the difference between two pointers (libc equivalent ptrdiff_t) + +## constants +in ``, every type has an associated min and max constant, containing the smallest and largest value that type can hold on your system. these can be access by suffixing a type with `_min` and `_max`, respectively. min and max values of native types can be accessed with the `kc_[us]` prefix - for instance, the minimum value of `signed long` is `kc_slong_min`. (`long long` can be referenced as `llong`). + + * `byte_bits` - the bit length of ubyte, sbyte, and char; that is, the number of bits in the type `sizeof` measures things in terms of. `sizeof(type) * byte_bits` will always return the number of bits in a type. ### struct kenv `kenv` is a struct that encompasses the environment the program was launched in. * `kiochan std` - a stereo IO channel for reading and writing to and from stdout. * `kiochan err` - a mono IO channel for writing to stderr. @@ -35,11 +44,11 @@ ## functions ### kstop() -`noreturn void kstop(stat)` terminates the program immediately, returning the specified integer to the OS as an exit status. the type of integer it takes depends on your operating system. consider using the `enum kbad` defines in ``, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (``, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (``). ## definitions kcore is the only module that defines any terms outside the k- namespace. the only terms it so defines are native C terms like `noreturn`, which are implemented as keywords in a reserved namespace (`_` followed by an uppercase letter; in this case, `_Noreturn`). macros are then defined in new headers for the "natural" version of the term in order to avoid breaking older code. examples of this technique are `` and ``. since libk is designed for new, modern code, breaking old code isn't a concern, and we turn on all these new keywords as soon as you load ``. Index: kcore/type.h.m ================================================================== --- kcore/type.h.m +++ kcore/type.h.m @@ -5,93 +5,121 @@ --- needs. it will be emitted as . --- vim: ft=c #ifndef KItype #define KItype -typedef unsigned char kc_uint_min; -typedef signed char kc_sint_min; -typedef unsigned long long kc_uint_max; -typedef signed long long kc_sint_max; - -[ifdef type_bit8] - typedef unsigned [type_bit8] u8; - typedef signed [type_bit8] s8; -[else] - typedef kc_uint_min u8; - typedef kc_sint_min s8; -[endif] - -[ifdef type_bit16] - typedef unsigned [type_bit16] u16; - typedef signed [type_bit16] s16; -[else] - typedef kc_uint_max u16; - typedef kc_sint_max s16; -[endif] - -[ifdef type_bit32] - typedef unsigned [type_bit32] u32; - typedef signed [type_bit32] s32; -[else] - typedef kc_uint_max u32; - typedef kc_sint_max s32; -[endif] +/* we define 64-bit types first due to an oddity in how + * 128-bit types are handled: we want kc_?big to reference + * the absolute largest type available to the compiler, + * but in some cases, 128-bits may not be among the + * standard C types despite being supported by the + * compiler. to work around this, we first check whether + * 64-bit types are available (__int128_t only works on + * 64-bit systems) and then whether the compiler is one + * that supports the 128-bit extension - but only if a + * native 128-bit type is not available. + * + * once this is done, we can be certain that u128 will + * reference the largest available integer type and can + * safely define kc_?big by reference to it. */ [ifdef type_bit64] typedef unsigned [type_bit64] u64; typedef signed [type_bit64] s64; [ifndef type_bit128] + /* even if no native type is 128 bits long, clang and + * gcc have extensions to support 128 bit arithmetic + * on 64-bit hardware */ # if defined(__GNUC__) || defined(__clang__) typedef unsigned __int128_t u128; typedef signed __int128_t s128; # else - typedef kc_uint_max u128; - typedef kc_sint_max s128; + /* if we don't have access to that extension + * or native 128-bit types, then we just use + * the largest native type specified in the + * C standard */ + typedef unsigned long long u128; + typedef signed long long s128; # endif [endif] [else] - typedef kc_uint_max u64; - typedef kc_sint_max s64; + typedef unsigned long long u64; + typedef signed long long s64; - typedef kc_uint_max u128; - typedef kc_sint_max s128; + typedef u64 u128; + typedef s64 s128; [endif] [ifdef type_bit128] typedef unsigned [type_bit128] u128; typedef signed [type_bit128] s128; [endif] + +typedef unsigned char ubyte; +typedef signed char sbyte; +typedef u128 ubig; +typedef s128 sbig; + +[ifdef type_bit8] + typedef unsigned [type_bit8] u8; + typedef signed [type_bit8] s8; +[else] + typedef ubyte u8; + typedef sbyte s8; +[endif] + +[ifdef type_bit16] + typedef unsigned [type_bit16] u16; + typedef signed [type_bit16] s16; +[else] + typedef ubig u16; + typedef sbig s16; +[endif] + +[ifdef type_bit32] + typedef unsigned [type_bit32] u32; + typedef signed [type_bit32] s32; +[else] + typedef ubig u32; + typedef sbig s32; +[endif] enum /* max-min values of each type */ { - /* assuming two's complement. TODO: check math */ - /* TODO: figure out how to calc min */ - kc_byte_bits = [byte_bits], + byte_bits = [byte_bits], + u8_min = 0, u8_max = ((u8)-1), u16_min = 0, u16_max = ((u16)-1), u32_min = 0, u32_max = ((u32)-1), u64_min = 0, u32_max = ((u64)-1), u128_min = 0, u128_max = ((u128)-1), + /* assuming two's complement. TODO: check math */ [define merge: $1$2] [define [sspec type]: [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] [sspec s8], [sspec s16], [sspec s32], [sspec s64], [sspec s128], - kc_min_uchar = 0, kc_max_uchar = [type_max_u_char], - kc_min_ushort = 0, kc_max_ushort = [type_max_u_short], - kc_min_uint = 0, kc_max_uint = [type_max_u_int], - kc_min_ulong = 0, kc_max_ulong = [type_max_u_long], - kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong], + kc_uchar_min = 0, kc_uchar_max = [type_max_u_char], + kc_ushort_min = 0, kc_ushort_max = [type_max_u_short], + kc_uint_min = 0, kc_uint_max = [type_max_u_int], + kc_ulong_min = 0, kc_ulong_max = [type_max_u_long], + kc_ullong_min = 0, kc_ullong_max = [type_max_u_llong], + + kc_schar_min = [type_min_s_char], kc_schar_max = [type_max_s_char], + kc_sshort_min = [type_min_s_short], kc_sshort_max = [type_max_s_short], + kc_sint_min = [type_min_s_int], kc_sint_max = [type_max_s_int], + kc_slong_min = [type_min_s_long], kc_slong_max = [type_max_s_long], + kc_sllong_min = [type_min_s_llong], kc_sllong_max = [type_max_s_llong], + + ubig_min = u128_min, ubig_max = u128_max, + sbig_min = s128_min, sbig_max = s128_max, - kc_min_schar = [type_min_s_char], kc_max_schar = [type_max_s_char], - kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short], - kc_min_sint = [type_min_s_int], kc_max_sint = [type_max_s_int], - kc_min_slong = [type_min_s_long], kc_max_slong = [type_max_s_long], - kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong], + ubyte_min = kc_uchar_min, ubyte_max = kc_uchar_max, + sbyte_min = kc_schar_min, sbyte_max = kc_schar_max, }; [ifdef type_sz] typedef [type_sz] sz; [else] @@ -104,11 +132,11 @@ # else /* we're stumped - set sz to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative sz (size_t) type definition \ available; defaulting to largest unsigned integer type - typedef kc_uint_max sz; + typedef ubig sz; # endif # endif [endif] [ifdef type_offset] @@ -123,11 +151,11 @@ # else /* no dice - set offset to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative offset (ptrdiff_t) type definition \ available; defaulting to largest unsigned integer type - typedef kc_sint_max offset; + typedef sbig offset; # endif # endif [endif] // exit status integer types - pls use kbad in instead