Explorar o código

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill %!s(int64=4) %!d(string=hai) anos
pai
achega
56078ee099

+ 73 - 0
core/c/libc/README.md

@@ -0,0 +1,73 @@
+# C support
+
+The following is a mostly-complete projection of the C11 standard library as defined by the C11 specification: N1570, or ISO/IEC 9899:2011. Only the macros, types, and functions as required by the standard are projected. Extensions to C, such as POSIX are not handled by these bindings, this is otherwise portable to any implementation which can support a hosted C runtime.
+
+## Support matrix
+| Header            | Status                                             |
+|:------------------|:---------------------------------------------------|
+| `<assert.h>`      | Not applicable, use Odin's `#assert`               |
+| `<complex.h>`     | Mostly projected, see [limitations](#Limitations)  |
+| `<ctype.h>`       | Fully projected                                    |
+| `<errno.h>`       | Fully projected                                    |
+| `<fenv.h>`        | Not projected                                      |
+| `<float.h>`       | Not projected                                      |
+| `<inttypes.h>`    | Fully projected                                    |
+| `<iso646.h>`      | Not applicable, use Odin's operators               |
+| `<limits.h>`      | Not projected                                      |
+| `<locale.h>`      | Not projected                                      |
+| `<math.h>`        | Mostly projected, see [limitations](#Limitations)  |
+| `<setjmp.h>`      | Fully projected                                    |
+| `<signal.h>`      | Fully projected                                    |
+| `<stdalign.h>`    | Not applicable, use Odin's `#align`                |
+| `<stdarg.h>`      | Mostly projected, see [limitations](#Limitations)  |
+| `<stdatomic.h>`   | Fully projected                                    |
+| `<stdbool.h>`     | Not applicable, use Odin's `b32`                   |
+| `<stddef.h>`      | Mostly projected, see [limitations](#Limitations)  |
+| `<stdint.h>`      | Fully projected                                    |
+| `<stdio.h>`       | Fully projected                                    |
+| `<stdlib.h>`      | Fully projected                                    |
+| `<stdnoreturn.h>` | Not applicable, use Odin's divergent return `!`    |
+| `<string.h>`      | Fully projected                                    |
+| `<tgmath.h>`      | Mostly projected, see [limitations](#Limitations)  |
+| `<threads.h>`     | Fully projected                                    |
+| `<time.h>`        | Fully projected                                    |
+| `<uchar.h>`       | Fully projected                                    |
+| `<wchar.h>`       | Fully projected                                    |
+| `<wctype.h>`      | Fully projected                                    |
+
+## Limitations
+Not all C standard library functionality can be fully projected due to language differences. These limitations are listed here.
+
+### `long double`
+As Odin lacks a means to interact with `long double` in it's foreign interface, this projection effort does not bind or define anything requiring `long double` which is permitted by the C standard.
+
+### `<complex.h>`
+The special values `_Complex_I`, `_Imaginary_I` and the appropriate definition of `I` cannot be realized with the same type in Odin as it would be in C. The literal `1i` is tempting to use for these definitions but the semantics differ from C and would be confusing to use.
+
+### `<math.h>`
+The classification functions, e.g: `fpclassify` are required by C to be implemented as macros, meaning no implementation would expose functions in their library we could bind. Instead, we provide native Odin implementations with functionally equivalent semantics and behavior as the C ones. Unfortunately, since classification returns unspecified constant values this may be an ABI break where the value of those constants enter and exit native C code.
+
+### `<stdarg.h>`
+While Odin can interact with variable argument C functions through the use of the `#c_vararg` attribute within a foreign block, it's not actually possible to create procedures in Odin with bodies that have the same ABI as that of variable argument C functions, as a result `va_arg` is not projected.
+
+### `<stddef.h>`
+`offsetof` is not realizable in Odin, however you can use `offset_of` instead.
+
+### `<tgmath.h>`
+C has some strange promotion and type-coercion behavior for `<tgmath.h>` which isn't correctly handled by this projection, specifically involving the use of complex arithmetic and kernels. We do mostly support type-generic math through the use of Odin's explicit procedure overloading, however the semantic behavior of that doesn't match C and so literal expressions of complex type in C may not call the same underlying math kernel functions as they do in Odin through this projection.
+
+## Caveats
+
+In addition to limitations, there are some minor caveats you should be aware when using this projection.
+
+* `errno()` is a function which returns `^int` rather than a macro.
+* `MB_CUR_MAX()` is a function which return `size_t` rather than a macro.
+* Currently only works on Windows (MSVCRT) and Linux (GLIBC or MUSL)
+
+## License
+Every file within this directory is made available under Odin's BSD-2 license
+with the following copyright.
+
+```
+Copyright 2021 Dale Weiler <[email protected]>.
+```

+ 78 - 0
core/c/libc/complex.odin

@@ -0,0 +1,78 @@
+package libc
+
+// 7.3 Complex arithmetic
+
+foreign import libc "system:c"
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.3.5 Trigonometric functions
+	cacos   :: proc(z: complex_double) -> complex_double ---;
+	cacosf  :: proc(z: complex_float) -> complex_float ---;
+	casin   :: proc(z: complex_double) -> complex_double ---;
+	casinf  :: proc(z: complex_float) -> complex_float ---;
+	catan   :: proc(z: complex_double) -> complex_double ---;
+	catanf  :: proc(z: complex_float) -> complex_float ---;
+	ccos    :: proc(z: complex_double) -> complex_double ---;
+	ccosf   :: proc(z: complex_float) -> complex_float ---;
+	csin    :: proc(z: complex_double) -> complex_double ---;
+	csinf   :: proc(z: complex_float) -> complex_float ---;
+	ctan    :: proc(z: complex_double) -> complex_double ---;
+	ctanf   :: proc(z: complex_float) -> complex_float ---;
+
+	// 7.3.6 Hyperbolic functions
+	cacosh  :: proc(z: complex_double) -> complex_double ---;
+	cacoshf :: proc(z: complex_float) -> complex_float ---;
+	casinh  :: proc(z: complex_double) -> complex_double ---;
+	casinhf :: proc(z: complex_float) -> complex_float ---;
+	catanh  :: proc(z: complex_double) -> complex_double ---;
+	catanhf :: proc(z: complex_float) -> complex_float ---;
+	ccosh   :: proc(z: complex_double) -> complex_double ---;
+	ccoshf  :: proc(z: complex_float) -> complex_float ---;
+	csinh   :: proc(z: complex_double) -> complex_double ---;
+	csinhf  :: proc(z: complex_float) -> complex_float ---;
+	ctanh   :: proc(z: complex_double) -> complex_double ---;
+	ctanhf  :: proc(z: complex_float) -> complex_float ---;
+
+	// 7.3.7 Exponential and logarithmic functions
+	cexp    :: proc(z: complex_double) -> complex_double ---;
+	cexpf   :: proc(z: complex_float) -> complex_float ---;
+	clog    :: proc(z: complex_double) -> complex_double ---;
+	clogf   :: proc(z: complex_float) -> complex_float ---;
+
+	// 7.3.8 Power and absolute-value functions
+	cabs    :: proc(z: complex_double) -> complex_double ---;
+	cabsf   :: proc(z: complex_float) -> complex_float ---;
+	cpow    :: proc(z: complex_double) -> complex_double ---;
+	cpowf   :: proc(z: complex_float) -> complex_float ---;
+	csqrt   :: proc(z: complex_double) -> complex_double ---;
+	csqrtf  :: proc(z: complex_float) -> complex_float ---;
+
+	// 7.3.9 Manipulation functions
+	carg    :: proc(z: complex_double) -> double ---;
+	cargf   :: proc(z: complex_float) -> float ---;
+	cimag   :: proc(z: complex_double) -> double ---;
+	cimagf  :: proc(z: complex_float) -> float ---;
+	conj    :: proc(z: complex_double) -> complex_double ---;
+	conjf   :: proc(z: complex_float) -> complex_float ---;
+	cproj   :: proc(z: complex_double) -> complex_double ---;
+	cprojf  :: proc(z: complex_float) -> complex_float ---;
+	creal   :: proc(z: complex_double) -> double ---;
+	crealf  :: proc(z: complex_float) -> float ---;
+}
+
+import builtin "core:builtin"
+
+complex_float  :: distinct builtin.complex64;
+complex_double :: distinct builtin.complex128;
+
+// Cannot implement _Complex_I or _Imaginary_I in Odin, thus
+// complex and imaginary cannot be implement either.
+
+CMPLX :: #force_inline proc(x, y: double) -> complex_double {
+	return builtin.complex(x, y);
+}
+
+CMPLXF :: #force_inline proc(x, y: float) -> complex_float {
+	return builtin.complex(x, y);
+}

+ 26 - 0
core/c/libc/ctype.odin

@@ -0,0 +1,26 @@
+package libc
+
+foreign import libc "system:c"
+
+// 7.4 Character handling
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.4.1 Character classification functions
+	isalnum  :: proc(c: int) -> int ---;
+	isalpha  :: proc(c: int) -> int ---;
+	isblank  :: proc(c: int) -> int ---;
+	iscntrl  :: proc(c: int) -> int ---;
+	isdigit  :: proc(c: int) -> int ---;
+	isgraph  :: proc(c: int) -> int ---;
+	islower  :: proc(c: int) -> int ---;
+	isprint  :: proc(c: int) -> int ---;
+	ispunct  :: proc(c: int) -> int ---;
+	isspace  :: proc(c: int) -> int ---;
+	isupper  :: proc(c: int) -> int ---;
+	isxdigit :: proc(c: int) -> int ---;
+
+	// 7.4.2 Character case mapping functions
+	tolower  :: proc(c: int) -> int ---;
+	toupper  :: proc(c: int) -> int ---;
+}

+ 43 - 0
core/c/libc/errno.odin

@@ -0,0 +1,43 @@
+package libc
+
+// 7.5 Errors
+
+foreign import libc "system:c"
+
+// C11 standard only requires the definition of:
+//	EDOM,
+//	EILSEQ
+//	ERANGE
+when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		@(link_name="__libc_errno_location")
+		_get_errno :: proc() -> ^int ---;
+	}
+
+	EDOM   :: 33;
+	EILSEQ :: 84;
+	ERANGE :: 34;
+}
+
+when ODIN_OS == "windows" {
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		@(link_name="_errno")
+		_get_errno :: proc() -> ^int ---;
+	}
+
+	EDOM   :: 33;
+	EILSEQ :: 42;
+	ERANGE :: 34;
+}
+
+// Odin has no way to make an identifier "errno" behave as a function call to
+// read the value, or to produce an lvalue such that you can assign a different
+// error value to errno. To work around this, just expose it as a function like
+// it actually is.
+errno :: #force_inline proc() -> ^int {
+	return _get_errno();
+}

+ 396 - 0
core/c/libc/math.odin

@@ -0,0 +1,396 @@
+package libc
+
+// 7.12 Mathematics
+
+import "core:intrinsics"
+
+foreign import libc "system:c"
+
+// To support C's tgmath behavior we use Odin's explicit procedure overloading,
+// but we cannot use the same names as exported by libc so use @(link_name)
+// and keep them as private symbols of name "libc_"
+@(private="file")
+@(default_calling_convention="c")
+foreign libc {
+	// 7.12.4 Trigonometric functions
+	@(link_name="acos")       libc_acos       :: proc(x: double) -> double ---;
+	@(link_name="acosf")      libc_acosf      :: proc(x: float) -> float ---;
+	@(link_name="asin")       libc_asin       :: proc(x: double) -> double ---;
+	@(link_name="asinf")      libc_asinf      :: proc(x: float) -> float ---;
+	@(link_name="atan")       libc_atan       :: proc(x: double) -> double ---;
+	@(link_name="atanf")      libc_atanf      :: proc(x: float) -> float ---;
+	@(link_name="atan2")      libc_atan2      :: proc(y: double, x: double) -> double ---;
+	@(link_name="atan2f")     libc_atan2f     :: proc(y: float, x: float) -> float ---;
+	@(link_name="cos")        libc_cos        :: proc(x: double) -> double ---;
+	@(link_name="cosf")       libc_cosf       :: proc(x: float) -> float ---;
+	@(link_name="sin")        libc_sin        :: proc(x: double) -> double ---;
+	@(link_name="sinf")       libc_sinf       :: proc(x: float) -> float ---;
+	@(link_name="tan")        libc_tan        :: proc(x: double) -> double ---;
+	@(link_name="tanf")       libc_tanf       :: proc(x: float) -> float ---;
+
+	// 7.12.5 Hyperbolic functions
+	@(link_name="acosh")      libc_acosh      :: proc(x: double) -> double ---;
+	@(link_name="acoshf")     libc_acoshf     :: proc(x: float) -> float ---;
+	@(link_name="asinh")      libc_asinh      :: proc(x: double) -> double ---;
+	@(link_name="asinhf")     libc_asinhf     :: proc(x: float) -> float ---;
+	@(link_name="atanh")      libc_atanh      :: proc(x: double) -> double ---;
+	@(link_name="atanhf")     libc_atanhf     :: proc(x: float) -> float ---;
+	@(link_name="cosh")       libc_cosh       :: proc(x: double) -> double ---;
+	@(link_name="coshf")      libc_coshf      :: proc(x: float) -> float ---;
+	@(link_name="sinh")       libc_sinh       :: proc(x: double) -> double ---;
+	@(link_name="sinhf")      libc_sinhf      :: proc(x: float) -> float ---;
+	@(link_name="tanh")       libc_tanh       :: proc(x: double) -> double ---;
+	@(link_name="tanhf")      libc_tanhf      :: proc(x: float) -> float ---;
+
+	// 7.12.6 Exponential and logarithmic functions
+	@(link_name="exp")        libc_exp        :: proc(x: double) -> double ---;
+	@(link_name="expf")       libc_expf       :: proc(x: float) -> float ---;
+	@(link_name="exp2")       libc_exp2       :: proc(x: double) -> double ---;
+	@(link_name="exp2f")      libc_exp2f      :: proc(x: float) -> float ---;
+	@(link_name="expm1")      libc_expm1      :: proc(x: double) -> double ---;
+	@(link_name="expm1f")     libc_expm1f     :: proc(x: float) -> float ---;
+	@(link_name="frexp")      libc_frexp      :: proc(value: double, exp: ^int) -> double ---;
+	@(link_name="frexpf")     libc_frexpf     :: proc(value: float, exp: ^int) -> float ---;
+	@(link_name="ilogb")      libc_ilogb      :: proc(x: double) -> int ---;
+	@(link_name="ilogbf")     libc_ilogbf     :: proc(x: float) -> int ---;
+	@(link_name="ldexp")      libc_ldexp      :: proc(x: double, exp: int) -> double ---;
+	@(link_name="ldexpf")     libc_ldexpf     :: proc(x: float, exp: int) -> float ---;
+	@(link_name="log")        libc_log        :: proc(x: double) -> double ---;
+	@(link_name="logf")       libc_logf       :: proc(x: float) -> float ---;
+	@(link_name="log10")      libc_log10      :: proc(x: double) -> double ---;
+	@(link_name="log10f")     libc_log10f     :: proc(x: float) -> float ---;
+	@(link_name="log1p")      libc_log1p      :: proc(x: double) -> double ---;
+	@(link_name="log1pf")     libc_log1pf     :: proc(x: float) -> float ---;
+	@(link_name="log2")       libc_log2       :: proc(x: double) -> double ---;
+	@(link_name="log2f")      libc_log2f      :: proc(x: float) -> float ---;
+	@(link_name="logb")       libc_logb       :: proc(x: double) -> double ---;
+	@(link_name="logbf")      libc_logbf      :: proc(x: float) -> float ---;
+	@(link_name="modf")       libc_modf       :: proc(value: double, iptr: ^double) -> double ---;
+	@(link_name="modff")      libc_modff      :: proc(value: float, iptr: ^float) -> float ---;
+	@(link_name="scalbn")     libc_scalbn     :: proc(x: double, n: int) -> double ---;
+	@(link_name="scalbnf")    libc_scalbnf    :: proc(x: float, n: int) -> float ---;
+	@(link_name="scalbln")    libc_scalbln    :: proc(x: double, n: long) -> double ---;
+	@(link_name="scalblnf")   libc_scalblnf   :: proc(x: float, n: long) -> float ---;
+
+	// 7.12.7 Power and absolute-value functions
+	@(link_name="cbrt")       libc_cbrt       :: proc(x: double) -> double ---;
+	@(link_name="cbrtf")      libc_cbrtf      :: proc(x: float) -> float ---;
+	@(link_name="fabs")       libc_fabs       :: proc(x: double) -> double ---;
+	@(link_name="fabsf")      libc_fabsf      :: proc(x: float) -> float ---;
+	@(link_name="hypot")      libc_hypot      :: proc(x: double, y: double) -> double ---;
+	@(link_name="hypotf")     libc_hypotf     :: proc(x: float, y: float) -> float ---;
+	@(link_name="pow")        libc_pow        :: proc(x: double, y: double) -> double ---;
+	@(link_name="powf")       libc_powf       :: proc(x: float, y: float) -> float ---;
+	@(link_name="sqrt")       libc_sqrt       :: proc(x: double) -> double ---;
+	@(link_name="sqrtf")      libc_sqrtf      :: proc(x: float) -> float ---;
+
+	// 7.12.8 Error and gamma functions
+	@(link_name="erf")        libc_erf        :: proc(x: double) -> double ---;
+	@(link_name="erff")       libc_erff       :: proc(x: float) -> float ---;
+	@(link_name="erfc")       libc_erfc       :: proc(x: double) -> double ---;
+	@(link_name="erfcf")      libc_erfcf      :: proc(x: float) -> float ---;
+	@(link_name="lgamma")     libc_lgamma     :: proc(x: double) -> double ---;
+	@(link_name="lgammaf")    libc_lgammaf    :: proc(x: float) -> float ---;
+	@(link_name="tgamma")     libc_tgamma     :: proc(x: double) -> double ---;
+	@(link_name="tgammaf")    libc_tgammaf    :: proc(x: float) -> float ---;
+
+	// 7.12.9 Nearest integer functions
+	@(link_name="ceil")       libc_ceil       :: proc(x: double) -> double ---;
+	@(link_name="ceilf")      libc_ceilf      :: proc(x: float) -> float ---;
+	@(link_name="floor")      libc_floor      :: proc(x: double) -> double ---;
+	@(link_name="floorf")     libc_floorf     :: proc(x: float) -> float ---;
+	@(link_name="nearbyint")  libc_nearbyint  :: proc(x: double) -> double ---;
+	@(link_name="nearbyintf") libc_nearbyintf :: proc(x: float) -> float ---;
+	@(link_name="rint")       libc_rint       :: proc(x: double) -> double ---;
+	@(link_name="rintf")      libc_rintf      :: proc(x: float) -> float ---;
+	@(link_name="lrint")      libc_lrint      :: proc(x: double) -> long ---;
+	@(link_name="lrintf")     libc_lrintf     :: proc(x: float) -> long ---;
+	@(link_name="llrint")     libc_llrint     :: proc(x: double) -> longlong ---;
+	@(link_name="llrintf")    libc_llrintf    :: proc(x: float) -> longlong ---;
+	@(link_name="round")      libc_round      :: proc(x: double) -> double ---;
+	@(link_name="roundf")     libc_roundf     :: proc(x: float) -> float ---;
+	@(link_name="lround")     libc_lround     :: proc(x: double) -> long ---;
+	@(link_name="lroundf")    libc_lroundf    :: proc(x: float) -> long ---;
+	@(link_name="llround")    libc_llround    :: proc(x: double) -> longlong ---;
+	@(link_name="llroundf")   libc_llroundf   :: proc(x: float) -> longlong ---;
+	@(link_name="trunc")      libc_trunc      :: proc(x: double) -> double ---;
+	@(link_name="truncf")     libc_truncf     :: proc(x: float) -> float ---;
+
+	// 7.12.10 Remainder functions
+	@(link_name="fmod")       libc_fmod       :: proc(x: double, y: double) -> double ---;
+	@(link_name="fmodf")      libc_fmodf      :: proc(x: float, y: float) -> float ---;
+	@(link_name="remainder")  libc_remainder  :: proc(x: double, y: double) -> double ---;
+	@(link_name="remainderf") libc_remainderf :: proc(x: float, y: float) -> float ---;
+	@(link_name="remquo")     libc_remquo     :: proc(x: double, y: double, quo: ^int) -> double ---;
+	@(link_name="remquof")    libc_remquof    :: proc(x: float, y: float, quo: ^int) -> float ---;
+
+	// 7.12.11 Manipulation functions
+	@(link_name="copysign")   libc_copysign   :: proc(x: double, y: double) -> double ---;
+	@(link_name="copysignf")  libc_copysignf  :: proc(x: float, y: float) -> float ---;
+	@(link_name="nan")        libc_nan        :: proc(tagp: cstring) -> double ---;
+	@(link_name="nanf")       libc_nanf       :: proc(tagp: cstring) -> float ---;
+	@(link_name="nextafter")  libc_nextafter  :: proc(x: double, y: double) -> double ---;
+	@(link_name="nextafterf") libc_nextafterf :: proc(x: float, y: float) -> float ---;
+
+	// 7.12.12 Maximum, minimum, and positive difference functions
+	@(link_name="fdim")       libc_fdim       :: proc(x: double, y: double) -> double ---;
+	@(link_name="fdimf")      libc_fdimf      :: proc(x: float, y: float) -> float ---;
+	@(link_name="fmax")       libc_fmax       :: proc(x: double, y: double) -> double ---;
+	@(link_name="fmaxf")      libc_fmaxf      :: proc(x: float, y: float) -> float ---;
+	@(link_name="fmin")       libc_fmin       :: proc(x: double, y: double) -> double ---;
+	@(link_name="fminf")      libc_fminf      :: proc(x: float, y: float) -> float ---;
+	@(link_name="fma")        libc_fma        :: proc(x, y, z: double) -> double ---;
+	@(link_name="fmaf")       libc_fmaf       :: proc(x, y, z: float) -> float ---;
+}
+
+@(private="file")
+_nan_bit_pattern := ~u64(0);
+
+// On amd64 Windows and Linux, float_t and double_t are respectively both
+// their usual types. On x86 it's not possible to define these types correctly
+// since they would be long double which Odin does have support for.
+float_t          :: float;
+double_t         :: double;
+
+NAN              := transmute(double)(_nan_bit_pattern);
+INFINITY         :: 1e5000;
+
+HUGE_VALF        :: INFINITY;
+HUGE_VAL         :: double(INFINITY);
+
+MATH_ERRNO       :: 1;
+MATH_ERREXCEPT   :: 2;
+
+math_errhandling :: 2; // Windows, Linux, macOS all use this mode.
+
+FP_ILOGBNAN      :: -1 - int((~uint(0)) >> 1);
+FP_ILOGB0        :: FP_ILOGBNAN;
+
+// Number classification constants. These do not have to match libc since we
+// implement our own classification functions as libc requires they be macros,
+// which means libc does not export standard functions for them.
+FP_NAN           :: 0;
+FP_INFINITE      :: 1;
+FP_ZERO          :: 2;
+FP_NORMAL        :: 3;
+FP_SUBNORMAL     :: 4;
+
+@(private)
+_fpclassify :: #force_inline proc(x: double) -> int {
+	u := transmute(uint64_t)x;
+	e := u >> 52 & 0x7ff;
+	if e == 0     do return FP_SUBNORMAL if (u << 1)  != 0 else FP_ZERO;
+	if e == 0x7ff do return FP_NAN       if (u << 12) != 0 else FP_INFINITE;
+	return FP_NORMAL;
+}
+
+@(private)
+_fpclassifyf :: #force_inline proc(x: float) -> int {
+	u := transmute(uint32_t)x;
+	e := u >> 23 & 0xff;
+	if e == 0     do return FP_SUBNORMAL if (u << 1)  != 0 else FP_ZERO;
+	if e == 0xff  do return FP_NAN       if (u << 9)  != 0 else FP_INFINITE;
+	return FP_NORMAL;
+}
+
+@(private)
+_signbit :: #force_inline proc(x: double) -> int {
+	return int(transmute(uint64_t)x >> 63);
+}
+
+@(private)
+_signbitf :: #force_inline proc(x: float) -> int {
+	return int(transmute(uint32_t)x >> 31);
+}
+
+isfinite :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
+	return fpclassify(x) == FP_INFINITE;
+}
+
+isinf :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
+	return fpclassify(x) > FP_INFINITE;
+}
+
+isnan :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
+	return fpclassify(x) == FP_NAN;
+}
+
+isnormal :: #force_inline proc(x: $T) where intrinsics.type_is_float(T) {
+	return fpclassify(x) == FP_NORMAL;
+}
+
+// These are special in that they avoid float exceptions. They cannot just be
+// implemented as the relational comparisons, as that would produce an invalid
+// "sticky" state that propagates and affects maths results. These need
+// to be implemented natively in Odin assuming isunordered to prevent that.
+isgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	return !isunordered(x, y) && x > y;
+}
+
+isgreaterequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	return !isunordered(x, y) && x >= y;
+}
+
+isless :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	return !isunordered(x, y) && x < y;
+}
+
+islessequal :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	return !isunordered(x, y) && x <= y;
+}
+
+islessgreater :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	return !isunordered(x, y) && x <= y;
+}
+
+isunordered :: #force_inline proc(x, y: $T) where intrinsics.type_is_float(T) {
+	if isnan(x) {
+		// Force evaluation of y to propagate exceptions for ordering semantics.
+		// To ensure correct semantics of IEEE 754 this cannot be compiled away.
+		sink: T;
+		intrinsics.volatile_store(&sink, intrinsics.volatile_load(&y));
+		return true;
+	}
+	return isnan(y);
+}
+
+fpclassify :: proc{_fpclassify, _fpclassifyf};
+signbit    :: proc{_signbit, _signbitf};
+
+// Emulate tgmath.h behavior with explicit procedure overloading here.
+acos       :: proc{libc_acos, libc_acosf, cacos, cacosf};
+asin       :: proc{libc_asin, libc_asinf, casin, casinf};
+atan       :: proc{libc_atan, libc_atanf, catan, catanf};
+atan2      :: proc{libc_atan2, libc_atan2f};
+cos        :: proc{libc_cos, libc_cosf, ccos, ccosf};
+sin        :: proc{libc_sin, libc_sinf, csin, csinf};
+tan        :: proc{libc_tan, libc_tanf, ctan, ctanf};
+
+acosh      :: proc{libc_acosh, libc_acoshf, cacosh, cacoshf};
+asinh      :: proc{libc_asinh, libc_asinhf, casinh, casinhf};
+atanh      :: proc{libc_atanh, libc_atanhf, catanh, catanhf};
+cosh       :: proc{libc_cosh, libc_coshf, ccosh, ccoshf};
+sinh       :: proc{libc_sinh, libc_sinhf, csinh, csinhf};
+tanh       :: proc{libc_tanh, libc_tanhf, ctanh, ctanhf};
+
+exp        :: proc{libc_exp, libc_expf, cexp, cexpf};
+exp2       :: proc{libc_exp2, libc_exp2f}; 
+expm1      :: proc{libc_expm1, libc_expm1f};
+frexp      :: proc{libc_frexp, libc_frexpf};
+ilogb      :: proc{libc_ilogb, libc_ilogbf};
+ldexp      :: proc{libc_ldexp, libc_ldexpf};
+log        :: proc{libc_log, libc_logf, clog, clogf};
+log10      :: proc{libc_log10, libc_log10f};
+log1p      :: proc{libc_log1p, libc_log1pf};
+log2       :: proc{libc_log2, libc_log2f};
+logb       :: proc{libc_logb, libc_logbf};
+modf       :: proc{libc_modf, libc_modff};
+scalbn     :: proc{libc_scalbn, libc_scalbnf};
+scalbln    :: proc{libc_scalbln, libc_scalblnf};
+
+cbrt       :: proc{libc_cbrt, libc_cbrtf};
+fabs       :: proc{libc_fabs, libc_fabsf, cabs, cabsf};
+hypot      :: proc{libc_hypot, libc_hypotf};
+pow        :: proc{libc_pow, libc_powf, cpow, cpowf};
+sqrt       :: proc{libc_sqrt, libc_sqrtf, csqrt, csqrtf};
+
+erf        :: proc{libc_erf, libc_erff};
+erfc       :: proc{libc_erfc, libc_erfcf};
+lgamma     :: proc{libc_lgamma, libc_lgammaf};
+tgamma     :: proc{libc_tgamma, libc_tgammaf};
+
+ceil       :: proc{libc_ceil, libc_ceilf};
+floor      :: proc{libc_floor, libc_floorf};
+nearbyint  :: proc{libc_nearbyint, libc_nearbyintf};
+rint       :: proc{libc_rint, libc_rintf};
+lrint      :: proc{libc_lrint, libc_lrintf};
+llrint     :: proc{libc_llrint, libc_llrintf};
+round      :: proc{libc_round, libc_roundf};
+lround     :: proc{libc_lround, libc_lroundf};
+llround    :: proc{libc_llround, libc_llroundf};
+trunc      :: proc{libc_trunc, libc_truncf};
+
+fmod       :: proc{libc_fmod, libc_fmodf};
+remainder  :: proc{libc_remainder, libc_remainderf};
+remquo     :: proc{libc_remquo, libc_remquof};
+
+copysign   :: proc{libc_copysign, libc_copysignf};
+nextafter  :: proc{libc_nextafter, libc_nextafterf};
+
+fdim       :: proc{libc_fdim, libc_fdimf};
+fmax       :: proc{libc_fmax, libc_fmaxf};
+fmin       :: proc{libc_fmin, libc_fminf};
+fma        :: proc{libc_fma, libc_fmaf};
+
+// But retain the 'f' suffix-variant functions as well so they can be used,
+// a trick is used here where we use explicit procedrual overloading of one
+// procedure. This is done because the foreign block is marked @(private) and
+// aliasing functions does not remove privateness from the entity.
+acosf      :: proc{libc_acosf};
+asinf      :: proc{libc_asinf};
+atanf      :: proc{libc_atanf};
+atan2f     :: proc{libc_atan2f};
+cosf       :: proc{libc_cosf};
+sinf       :: proc{libc_sinf};
+tanf       :: proc{libc_tanf};
+
+acoshf     :: proc{libc_acoshf};
+asinhf     :: proc{libc_asinhf};
+atanhf     :: proc{libc_atanhf};
+coshf      :: proc{libc_coshf};
+sinhf      :: proc{libc_sinhf};
+tanhf      :: proc{libc_tanhf};
+
+expf       :: proc{libc_expf};
+exp2f      :: proc{libc_exp2f};
+expm1f     :: proc{libc_expm1f};
+frexpf     :: proc{libc_frexpf};
+ilogbf     :: proc{libc_ilogbf};
+ldexpf     :: proc{libc_ldexpf};
+logf       :: proc{libc_logf};
+log10f     :: proc{libc_log10f};
+log1pf     :: proc{libc_log1pf};
+log2f      :: proc{libc_log2f};
+logbf      :: proc{libc_logbf};
+modff      :: proc{libc_modff};
+scalbnf    :: proc{libc_scalbnf};
+scalblnf   :: proc{libc_scalblnf};
+
+cbrtf      :: proc{libc_cbrtf};
+fabsf      :: proc{libc_fabsf};
+hypotf     :: proc{libc_hypotf};
+powf       :: proc{libc_powf};
+sqrtf      :: proc{libc_sqrtf};
+
+erff       :: proc{libc_erff};
+erfcf      :: proc{libc_erfcf};
+lgammaf    :: proc{libc_lgammaf};
+tgammaf    :: proc{libc_tgammaf};
+
+ceilf      :: proc{libc_ceilf};
+floorf     :: proc{libc_floorf};
+nearbyintf :: proc{libc_nearbyintf};
+rintf      :: proc{libc_rintf};
+lrintf     :: proc{libc_lrintf};
+llrintf    :: proc{libc_llrintf};
+roundf     :: proc{libc_roundf};
+lroundf    :: proc{libc_lroundf};
+llroundf   :: proc{libc_llroundf};
+truncf     :: proc{libc_truncf};
+
+fmodf      :: proc{libc_fmodf};
+remainderf :: proc{libc_remainderf};
+remquof    :: proc{libc_remquof};
+
+copysignf  :: proc{libc_copysignf};
+nextafterf :: proc{libc_nextafterf};
+
+fdimf      :: proc{libc_fdimf}; 
+fmaxf      :: proc{libc_fmaxf};
+fminf      :: proc{libc_fminf};
+fmaf       :: proc{libc_fmaf};
+
+// These two functions are special and not made type generic in tgmath.h since
+// they only differ by their return type.
+nan        :: proc{libc_nan};
+nanf       :: proc{libc_nanf};

+ 31 - 0
core/c/libc/setjmp.odin

@@ -0,0 +1,31 @@
+package libc
+
+// 7.13 Nonlocal jumps
+
+foreign import libc "system:c"
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.13.1 Save calling environment
+	//
+	// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
+	// necessarily export a symbol named setjmp but rather _setjmp in the case
+	// of musl, glibc, BSD libc, and msvcrt.
+	@(link_name="_setjmp")
+	setjmp  :: proc(env: ^jmp_buf) -> int ---;
+
+	// 7.13.2 Restore calling environment
+	longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---;
+}
+
+// The C99 Rationale describes jmp_buf as being an array type for backward
+// compatibility. Odin does not need to honor this and couldn't as arrays in
+// Odin don't decay to pointers. It is somewhat easy for us to bind this, we
+// just need to ensure the structure contains enough storage with appropriate
+// alignment. Since there are no types in C with an alignment larger than
+// that of max_align_t, which cannot be larger than sizeof(long double) as any
+// other exposed type wouldn't be valid C, the maximum alignment possible in a
+// strictly conformant C implementation is 16 on the platforms we care about.
+// The choice of 4096 bytes for storage of this type is more than enough on all
+// relevant platforms.
+jmp_buf :: struct #align 16 { _: [4096]char, };

+ 39 - 0
core/c/libc/signal.odin

@@ -0,0 +1,39 @@
+package libc
+
+// 7.14 Signal handling
+
+foreign import libc "system:c"
+
+sig_atomic_t :: distinct atomic_int;
+
+@(default_calling_convention="c")
+foreign libc {
+	signal :: proc(sig: int, func: proc "c" (int)) -> proc "c" (int) ---;
+	raise  :: proc(sig: int) -> int ---;
+}
+
+when ODIN_OS == "windows" {
+	SIG_ERR :: rawptr(~uintptr(0)); 
+	SIG_DFL :: rawptr(uintptr(0));
+	SIG_IGN :: rawptr(uintptr(1));
+
+	SIGABRT :: 22;
+	SIGFPE  :: 8;
+	SIGILL  :: 4;
+	SIGINT  :: 2;
+	SIGSEGV :: 11;
+	SIGTERM :: 15;
+}
+
+when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
+	SIG_ERR  :: rawptr(~uintptr(0));
+	SIG_DFL  :: rawptr(uintptr(0));
+	SIG_IGN  :: rawptr(uintptr(1)); 
+
+	SIGABRT  :: 6;
+	SIGFPE   :: 8;
+	SIGILL   :: 4;
+	SIGINT   :: 2;
+	SIGSEGV  :: 11;
+	SIGTERM  :: 15;
+}

+ 43 - 0
core/c/libc/stdarg.odin

@@ -0,0 +1,43 @@
+package libc
+
+// 7.16 Variable arguments
+
+import "core:intrinsics"
+import "core:runtime"
+import "core:mem"
+
+@(private="file")
+@(default_calling_convention="none")
+foreign _ {
+	@(link_name="llvm.va_start") _va_start :: proc(arglist: ^i8) ---;
+	@(link_name="llvm.va_end")   _va_end   :: proc(arglist: ^i8) ---;
+	@(link_name="llvm.va_copy")  _va_copy  :: proc(dst, src: ^i8) ---;
+}
+
+// Since there are no types in C with an alignment larger than that of
+// max_align_t, which cannot be larger than sizeof(long double) as any other
+// exposed type wouldn't be valid C, the maximum alignment possible in a
+// strictly conformant C implementation is 16 on the platforms we care about.
+// The choice of 4096 bytes for storage of this type is more than enough on all
+// relevant platforms.
+va_list :: struct #align 16 {
+	_: [4096]u8,
+};
+
+va_start :: #force_inline proc(ap: ^va_list, _: any) {
+	_va_start(cast(^i8)ap);
+}
+
+va_end :: #force_inline proc(ap: ^va_list) {
+	_va_end(cast(^i8)ap);
+}
+
+va_copy :: #force_inline proc(dst, src: ^va_list) {
+	_va_copy(cast(^i8)dst, cast(^i8)src);
+}
+
+// We cannot provide va_arg as there is no way to create "C" style procedures
+// in Odin which take variable arguments the C way. The #c_vararg attribute only
+// exists for foreign imports. That being said, being able to copy a va_list,
+// as well as start and end one is necessary in some functions, the va_list
+// taking functions in libc as an example.

+ 416 - 0
core/c/libc/stdatomic.odin

@@ -0,0 +1,416 @@
+package libc
+
+// 7.17 Atomics
+
+import "core:intrinsics"
+
+ATOMIC_BOOL_LOCK_FREE     :: true;
+ATOMIC_CHAR_LOCK_FREE     :: true;
+ATOMIC_CHAR16_T_LOCK_FREE :: true;
+ATOMIC_CHAR32_T_LOCK_FREE :: true;
+ATOMIC_WCHAR_T_LOCK_FREE  :: true;
+ATOMIC_SHORT_LOCK_FREE    :: true;
+ATOMIC_INT_LOCK_FREE      :: true;
+ATOMIC_LONG_LOCK_FREE     :: true;
+ATOMIC_LLONG_LOCK_FREE    :: true;
+ATOMIC_POINTER_LOCK_FREE  :: true;
+
+// 7.17.3 Order and consistency
+memory_order :: enum int {
+	relaxed,
+	consume,
+	acquire,
+	release,
+	acq_rel,
+	seq_cst,
+}
+
+memory_order_relaxed :: memory_order.relaxed;
+memory_order_consume :: memory_order.consume;
+memory_order_acquire :: memory_order.acquire;
+memory_order_release :: memory_order.release;
+memory_order_acq_rel :: memory_order.acq_rel;
+memory_order_seq_cst :: memory_order.seq_cst;
+
+// 7.17.2 Initialization
+ATOMIC_VAR_INIT :: #force_inline proc(value: $T) -> T {
+	return value;
+}
+
+atomic_init :: #force_inline proc(obj: ^$T, value: T) {
+	intrinsics.atomic_store(obj, value);
+}
+
+kill_dependency :: #force_inline proc(value: $T) -> T {
+	return value;
+}
+
+// 7.17.4 Fences
+atomic_thread_fence :: #force_inline proc(order: memory_order) {
+	switch (order) {
+	case .relaxed:
+		return;
+	case .consume:
+		intrinsics.atomic_fence_acq();
+	case .acquire:
+		intrinsics.atomic_fence_acq();
+	case .release:
+		intrinsics.atomic_fence_rel();
+	case .acq_rel:
+		intrinsics.atomic_fence_acqrel();
+	case .seq_cst:
+		intrinsics.atomic_fence_acqrel();
+	}
+}
+
+atomic_signal_fence :: #force_inline proc(order: memory_order) {
+	atomic_thread_fence(order);
+}
+
+// 7.17.5 Lock-free property
+atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
+	return size_of(T) <= 8 && (intrinsics.type_is_integer(T) || intrinsics.type_is_pointer(T));
+}
+
+// 7.17.6 Atomic integer types
+atomic_bool           :: distinct bool;
+atomic_char           :: distinct char;
+atomic_schar          :: distinct char;
+atomic_uchar          :: distinct uchar;
+atomic_short          :: distinct short;
+atomic_ushort         :: distinct ushort;
+atomic_int            :: distinct int;
+atomic_uint           :: distinct uint;
+atomic_long           :: distinct long;
+atomic_ulong          :: distinct ulong;
+atomic_llong          :: distinct longlong;
+atomic_ullong         :: distinct ulonglong;
+atomic_char16_t       :: distinct char16_t;
+atomic_char32_t       :: distinct char32_t;
+atomic_wchar_t        :: distinct wchar_t;
+atomic_int_least8_t   :: distinct int_least8_t;
+atomic_uint_least8_t  :: distinct uint_least8_t;
+atomic_int_least16_t  :: distinct int_least16_t;
+atomic_uint_least16_t :: distinct uint_least16_t;
+atomic_int_least32_t  :: distinct int_least32_t;
+atomic_uint_least32_t :: distinct uint_least32_t;
+atomic_int_least64_t  :: distinct int_least64_t;
+atomic_uint_least64_t :: distinct uint_least64_t;
+atomic_int_fast8_t    :: distinct int_fast8_t;
+atomic_uint_fast8_t   :: distinct uint_fast8_t;
+atomic_int_fast16_t   :: distinct int_fast16_t;
+atomic_uint_fast16_t  :: distinct uint_fast16_t;
+atomic_int_fast32_t   :: distinct int_fast32_t;
+atomic_uint_fast32_t  :: distinct uint_fast32_t;
+atomic_int_fast64_t   :: distinct int_fast64_t;
+atomic_uint_fast64_t  :: distinct uint_fast64_t;
+atomic_intptr_t       :: distinct intptr_t;
+atomic_uintptr_t      :: distinct uintptr_t;
+atomic_size_t         :: distinct size_t;
+atomic_ptrdiff_t      :: distinct ptrdiff_t;
+atomic_intmax_t       :: distinct intmax_t;
+atomic_uintmax_t      :: distinct uintmax_t;
+
+// 7.17.7 Operations on atomic types
+atomic_store :: #force_inline proc(object: ^$T, desired: T) {
+	intrinsics.atomic_store(object, desired);
+}
+
+atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) {
+	assert(order != .consume);
+	assert(order != .acquire);
+	assert(order != .acq_rel);
+
+	#partial switch (order) {
+	case .relaxed:
+		intrinsics.atomic_store_relaxed(object, desired);
+	case .release:
+		intrinsics.atomic_store_rel(object, desired);
+	case .seq_cst:
+		intrinsics.atomic_store(object, desired);
+	}
+}
+
+atomic_load :: #force_inline proc(object: ^$T) -> T {
+	return intrinsics.atomic_load(object);
+}
+
+atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) {
+	assert(order != .release);
+	assert(order != .acq_rel);
+
+	#partial switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_load_relaxed(object);
+	case .consume:
+		return intrinsics.atomic_load_acq(object);
+	case .acquire:
+		return intrinsics.atomic_load_acq(object);
+	case .seq_cst:
+		return intrinsics.atomic_load(object);
+	}
+}
+
+atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
+	return intrinsics.atomic_xchg(object, desired);
+}
+
+atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_xchg_relaxed(object, desired);
+	case .consume:
+		return intrinsics.atomic_xchg_acq(object, desired);
+	case .acquire:
+		return intrinsics.atomic_xchg_acq(object, desired);
+	case .release:
+		return intrinsics.atomic_xchg_rel(object, desired);
+	case .acq_rel:
+		return intrinsics.atomic_xchg_acqrel(object, desired);
+	case .seq_cst:
+		return intrinsics.atomic_xchg(object, desired);
+	}
+	return false;
+}
+
+// C does not allow failure memory order to be order_release or acq_rel.
+// Similarly, it does not allow the failure order to be stronger than success
+// order. Since consume and acquire are both monotonic, we can count them as
+// one, for a total of three memory orders that are relevant in compare exchange.
+// 	relaxed, acquire (consume), seq_cst.
+// The requirement that the failure order cannot be stronger than success limits
+// the valid combinations for the failure order to this table:
+// 	[success = seq_cst, failure = seq_cst] => _
+// 	[success = acquire, failure = seq_cst] => acq
+// 	[success = release, failure = seq_cst] => rel
+// 	[success = acq_rel, failure = seq_cst] => acqrel
+// 	[success = relaxed, failure = relaxed] => relaxed
+// 	[success = seq_cst, failure = relaxed] => failrelaxed
+// 	[success = seq_cst, failure = acquire] => failacq
+// 	[success = acquire, failure = relaxed] => acq_failrelaxed
+// 	[success = acq_rel, failure = relaxed] => acqrel_failrelaxed
+atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) {
+	value, ok := intrinsics.atomic_cxchg(object, expected^, desired);
+	if !ok do expected^ = value;
+	return ok;
+}
+
+atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) {
+	assert(failure != .release);
+	assert(failure != .acq_rel);
+
+	value: T; ok: bool;
+	#partial switch (failure) {
+	case .seq_cst:
+		assert(success != .relaxed);
+		#partial switch (success) {
+		case .seq_cst:
+			value, ok := intrinsics.atomic_cxchg(object, expected^, desired);
+		case .acquire:
+			value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired);
+		case .consume:
+			value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired);
+		case .release:
+			value, ok := intrinsics.atomic_cxchg_rel(object, expected^, desired);
+		case .acq_rel:
+			value, ok := intrinsics.atomic_cxchg_acqrel(object, expected^, desired);
+		}
+	case .relaxed:
+		assert(success != .release);
+		#partial switch (success) {
+		case .relaxed:
+			value, ok := intrinsics.atomic_cxchg_relaxed(object, expected^, desired);
+		case .seq_cst:
+			value, ok := intrinsics.atomic_cxchg_failrelaxed(object, expected^, desired);
+		case .acquire:
+			value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired);
+		case .consume:
+			value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired);
+		case .acq_rel:
+			value, ok := intrinsics.atomic_cxchg_acqrel_failrelaxed(object, expected^, desired);
+		}
+	case .consume:
+		fallthrough;
+	case .acquire:
+		assert(success == .seq_cst);
+		value, ok := intrinsics.atomic_cxchg_failacq(object, expected^, desired);
+
+	}
+	if !ok do expected^ = value;
+	return ok;
+}
+
+atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) {
+	value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired);
+	if !ok do expected^ = value;
+	return ok;
+}
+
+atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) {
+	assert(failure != .release);
+	assert(failure != .acq_rel);
+
+	value: T; ok: bool;
+	#partial switch (failure) {
+	case .seq_cst:
+		assert(success != .relaxed);
+		#partial switch (success) {
+		case .seq_cst:
+			value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired);
+		case .acquire:
+			value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired);
+		case .consume:
+			value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired);
+		case .release:
+			value, ok := intrinsics.atomic_cxchgweak_rel(object, expected^, desired);
+		case .acq_rel:
+			value, ok := intrinsics.atomic_cxchgweak_acqrel(object, expected^, desired);
+		}
+	case .relaxed:
+		assert(success != .release);
+		#partial switch (success) {
+		case .relaxed:
+			value, ok := intrinsics.atomic_cxchgweak_relaxed(object, expected^, desired);
+		case .seq_cst:
+			value, ok := intrinsics.atomic_cxchgweak_failrelaxed(object, expected^, desired);
+		case .acquire:
+			value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired);
+		case .consume:
+			value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired);
+		case .acq_rel:
+			value, ok := intrinsics.atomic_cxchgweak_acqrel_failrelaxed(object, expected^, desired);
+		}
+	case .consume:
+		fallthrough;
+	case .acquire:
+		assert(success == .seq_cst);
+		value, ok := intrinsics.atomic_cxchgweak_failacq(object, expected^, desired);
+
+	}
+	if !ok do expected^ = value;
+	return ok;
+}
+
+// 7.17.7.5 The atomic_fetch and modify generic functions
+atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T {
+	return intrinsics.atomic_add(object, operand);
+}
+
+atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_add_relaxed(object, operand);
+	case .consume:
+		return intrinsics.atomic_add_acq(object, operand);
+	case .acquire:
+		return intrinsics.atomic_add_acq(object, operand);
+	case .release:
+		return intrinsics.atomic_add_rel(object, operand);
+	case .acq_rel:
+		return intrinsics.atomic_add_acqrel(object, operand);
+	case .seq_cst:
+		return intrinsics.atomic_add(object, operand);
+	}
+}
+
+atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T {
+	return intrinsics.atomic_sub(object, operand);
+}
+
+atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_sub_relaxed(object, operand);
+	case .consume:
+		return intrinsics.atomic_sub_acq(object, operand);
+	case .acquire:
+		return intrinsics.atomic_sub_acq(object, operand);
+	case .release:
+		return intrinsics.atomic_sub_rel(object, operand);
+	case .acq_rel:
+		return intrinsics.atomic_sub_acqrel(object, operand);
+	case .seq_cst:
+		return intrinsics.atomic_sub(object, operand);
+	}
+}
+
+atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T {
+	return intrinsics.atomic_or(object, operand);
+}
+
+atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_or_relaxed(object, operand);
+	case .consume:
+		return intrinsics.atomic_or_acq(object, operand);
+	case .acquire:
+		return intrinsics.atomic_or_acq(object, operand);
+	case .release:
+		return intrinsics.atomic_or_rel(object, operand);
+	case .acq_rel:
+		return intrinsics.atomic_or_acqrel(object, operand);
+	case .seq_cst:
+		return intrinsics.atomic_or(object, operand);
+	}
+}
+
+atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T {
+	return intrinsics.atomic_xor(object, operand);
+}
+
+atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_xor_relaxed(object, operand);
+	case .consume:
+		return intrinsics.atomic_xor_acq(object, operand);
+	case .acquire:
+		return intrinsics.atomic_xor_acq(object, operand);
+	case .release:
+		return intrinsics.atomic_xor_rel(object, operand);
+	case .acq_rel:
+		return intrinsics.atomic_xor_acqrel(object, operand);
+	case .seq_cst:
+		return intrinsics.atomic_xor(object, operand);
+	}
+}
+
+atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T {
+	return intrinsics.atomic_and(object, operand);
+}
+atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
+	switch (order) {
+	case .relaxed:
+		return intrinsics.atomic_and_relaxed(object, operand);
+	case .consume:
+		return intrinsics.atomic_and_acq(object, operand);
+	case .acquire:
+		return intrinsics.atomic_and_acq(object, operand);
+	case .release:
+		return intrinsics.atomic_and_rel(object, operand);
+	case .acq_rel:
+		return intrinsics.atomic_and_acqrel(object, operand);
+	case .seq_cst:
+		return intrinsics.atomic_and(object, operand);
+	}
+}
+
+// 7.17.8 Atomic flag type and operations
+atomic_flag :: distinct atomic_bool;
+
+atomic_flag_test_and_set :: #force_inline proc(flag: ^atomic_flag) -> bool {
+	return bool(atomic_exchange(flag, atomic_flag(true)));
+}
+
+atomic_flag_test_and_set_explicit :: #force_inline proc(flag: ^atomic_flag, order: memory_order) -> bool {
+	return bool(atomic_exchange_explicit(flag, atomic_flag(true), order));
+}
+
+atomic_flag_clear :: #force_inline proc(flag: ^atomic_flag) {
+	atomic_store(flag, atomic_flag(false));
+}
+
+atomic_flag_clear_explicit :: #force_inline proc(flag: ^atomic_flag, order: memory_order) {
+	atomic_store_explicit(flag, atomic_flag(false), order);
+}

+ 131 - 0
core/c/libc/stdio.odin

@@ -0,0 +1,131 @@
+package libc
+
+foreign import libc "system:c"
+
+// 7.21 Input/output
+
+FILE :: struct {};
+
+// MSVCRT compatible.
+when ODIN_OS == "windows" {
+	_IOFBF       :: 0x0000;
+	_IONBF       :: 0x0004;
+	_IOLBF       :: 0x0040;
+
+	BUFSIZ       :: 512;
+
+	EOF          :: int(-1);
+
+	FOPEN_MAX    :: 20;
+
+	FILENAME_MAX :: 260;
+
+	L_tmpnam     :: 15; // "\\" + 12 + NUL
+
+	SEEK_SET     :: 0;
+	SEEK_CUR     :: 1;
+	SEEK_END     :: 2;
+
+	TMP_MAX      :: 32767; // SHRT_MAX
+
+	fpos_t       :: distinct i64;
+
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		__acrt_iob_func :: proc (index: uint) -> ^FILE ---;
+	}
+
+	stdin  := __acrt_iob_func(0);
+	stdout := __acrt_iob_func(1);
+	stderr := __acrt_iob_func(2);
+}
+
+// GLIBC and MUSL compatible.
+when ODIN_OS == "linux" {
+	fpos_t        :: struct #raw_union { _: [16]char, _: longlong, _: double, };
+
+	_IOFBF        :: 0;
+	_IOLBF        :: 1;
+	_IONBF        :: 2;
+
+	BUFSIZ        :: 1024;
+
+	EOF           :: int(-1);
+
+	FOPEN_MAX     :: 1000;
+
+	FILENAME_MAX  :: 4096;
+
+	L_tmpnam      :: 20;
+
+	SEEK_SET      :: 0;
+	SEEK_CUR      :: 1;
+	SEEK_END      :: 2;
+
+	TMP_MAX       :: 10000;
+
+	foreign libc {
+		stderr: ^FILE;
+		stdin:  ^FILE;
+		stdout: ^FILE;
+	}
+}
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.21.4 Operations on files
+	remove    :: proc(filename: cstring) -> int ---;
+	rename    :: proc(old, new: cstring) -> int ---;
+	tmpfile   :: proc() -> ^FILE ---;
+	tmpnam    :: proc(s: ^char) -> ^char ---;
+
+	// 7.21.5 File access functions
+	fclose    :: proc(stream: ^FILE) -> int ---;
+	fflush    :: proc(stream: ^FILE) -> int ---;
+	fopen     :: proc(filename, mode: cstring) -> ^FILE ---;
+	freopen   :: proc(filename, mode: cstring, stream: ^FILE) -> ^FILE ---;
+	setbuf    :: proc(stream: ^FILE, buf: ^char) ---;
+	setvbuf   :: proc(stream: ^FILE, buf: ^char, mode: int, size: size_t) -> int ---;
+
+	// 7.21.6 Formatted input/output functions
+	fprintf   :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---;
+	fscanf    :: proc(stream: ^FILE, format: cstring, #c_vararg args: ..any) -> int ---;
+	printf    :: proc(format: cstring, #c_vararg args: ..any) -> int ---;
+	scanf     :: proc(format: cstring, #c_vararg args: ..any) -> int ---;
+	snprintf  :: proc(s: ^char, format: cstring, #c_vararg args: ..any) -> int ---;
+	sscanf    :: proc(s, format: cstring, #c_vararg args: ..any) -> int ---;
+	vfprintf  :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---;
+	vfscanf   :: proc(stream: ^FILE, format: cstring, arg: ^va_list) -> int ---;
+	vprintf   :: proc(format: cstring, arg: ^va_list) -> int ---;
+	vscanf    :: proc(format: cstring, arg: ^va_list) -> int ---;
+	vsnprintf :: proc(s: ^char, n: size_t, format: cstring, arg: ^va_list) -> int ---;
+	vsprintf  :: proc(s: ^char, format: cstring, arg: ^va_list) -> int ---;
+	vsscanf   :: proc(s, format: cstring, arg: ^va_list) -> int ---;
+
+	// 7.21.7 Character input/output functions
+	fgetc     :: proc(stream: ^FILE) -> int ---;
+	fgets     :: proc(s: ^char, n: int, stream: ^FILE) -> ^char ---;
+	fputc     :: proc(s: cstring, stream: ^FILE) -> int ---;
+	getc      :: proc(stream: ^FILE) -> int ---;
+	getchar   :: proc() -> int ---;
+	putc      :: proc(c: int, stream: ^FILE) -> int ---;
+	putchar   :: proc() -> int ---;
+	puts      :: proc(s: cstring) -> int ---;
+	ungetc    :: proc(c: int, stream: ^FILE) -> int ---;
+	fread     :: proc(ptr: rawptr, size: size_t, stream: ^FILE) -> size_t ---;
+	fwrite    :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---;
+
+	// 7.21.9 File positioning functions
+	fgetpos   :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---;
+	fseek     :: proc(stream: ^FILE, offset: long, whence: int) -> int ---;
+	fsetpos   :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---;
+	ftell     :: proc(stream: ^FILE) -> long ---;
+	rewind    :: proc(stream: ^FILE) ---;
+
+	// 7.21.10 Error-handling functions
+	clearerr  :: proc(stream: ^FILE) ---;
+	feof      :: proc(stream: ^FILE) -> int ---;
+	ferror    :: proc(stream: ^FILE) -> int ---;
+	perror    :: proc(s: cstring) ---;
+}

+ 105 - 0
core/c/libc/stdlib.odin

@@ -0,0 +1,105 @@
+package libc
+
+// 7.22 General utilities
+
+foreign import libc "system:c"
+
+when ODIN_OS == "windows" {
+	RAND_MAX :: 0x7fff;
+
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		___mb_cur_max_func :: proc() -> int ---;
+	}
+
+	MB_CUR_MAX :: #force_inline proc() -> size_t {
+		return ___mb_cur_max_func();
+	}
+}
+
+when ODIN_OS == "linux" {
+	RAND_MAX :: 0x7fffffff;
+
+	// GLIBC and MUSL only
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		__ctype_get_mb_cur_max :: proc() -> size_t ---;
+	}
+
+	MB_CUR_MAX :: #force_inline proc() -> size_t {
+		return __ctype_get_mb_cur_max();
+	}
+}
+
+// C does not declare what these values should be, as an implementation is free
+// to use any two distinct values it wants to indicate success or failure.
+// However, nobody actually does and everyone appears to have agreed upon these
+// values.
+EXIT_SUCCESS :: 0;
+EXIT_FAILURE :: 1;
+
+// C does not declare which order 'quot' and 'rem' should be for the divide
+// structures. An implementation could put 'rem' first. However, nobody actually
+// does and everyone appears to have agreed upon this layout.
+div_t   :: struct { quot, rem: int, }
+ldiv_t  :: struct { quot, rem: long, }
+lldiv_t :: struct { quot, rem: longlong, }
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.22.1 Numeric conversion functions
+	atof          :: proc(nptr: cstring) -> double ---;
+	atoi          :: proc(nptr: cstring) -> int ---;
+	atol          :: proc(nptr: cstring) -> long ---;
+	atoll         :: proc(nptr: cstring) -> longlong ---;
+	strtod        :: proc(nptr: cstring, endptr: ^^char) -> double ---;
+	strtof        :: proc(nptr: cstring, endptr: ^^char) -> float ---;
+	strtol        :: proc(nptr: cstring, endptr: ^^char, base: int) -> long ---;
+	strtoll       :: proc(nptr: cstring, endptr: ^^char, base: int) -> longlong ---;
+	strtoul       :: proc(nptr: cstring, endptr: ^^char, base: int) -> ulong ---;
+	strtoull      :: proc(nptr: cstring, endptr: ^^char, base: int) -> ulonglong ---;
+
+	// 7.22.2 Pseudo-random sequence generation functions
+	rand          :: proc() -> int ---;
+	srand         :: proc(seed: uint) ---;
+
+	// 7.22.3 Memory management functions
+	aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---;
+	calloc        :: proc(nmemb, size: size_t) -> rawptr ---;
+	free          :: proc(ptr: rawptr) ---;
+	malloc        :: proc(size: size_t) -> rawptr ---;
+	realloc       :: proc(ptr: rawptr, size: size_t) -> rawptr ---;
+
+	// 7.22.4 Communication with the environment
+	abort         :: proc() -> ! ---;
+	atexit        :: proc(func: proc "c" ()) -> int ---;
+	at_quick_exit :: proc(func: proc "c" ()) -> int ---;
+	exit          :: proc(status: int) -> ! ---;
+	_Exit         :: proc(status: int) -> ! ---;
+	getenv        :: proc(name: cstring) -> ^char ---;
+	quick_exit    :: proc(status: int) -> ! ---;
+	system        :: proc(cmd: cstring) -> int ---;
+
+	// 7.22.5 Searching and sorting utilities
+	bsearch       :: proc(key, base: rawptr, nmemb, size: size_t, compar: proc "c" (lhs, rhs: rawptr) -> int) -> rawptr ---;
+	qsort         :: proc(base: rawptr, nmemb, size: size_t, compar: proc "c" (lhs, rhs: rawptr) -> int) ---;
+
+	// 7.22.6 Integer arithmetic functions
+	abs           :: proc(j: int) -> int ---;
+	labs          :: proc(j: long) -> long ---;
+	llabs         :: proc(j: longlong) -> longlong ---;
+	div           :: proc(numer, denom: int) -> div_t ---;
+	ldiv          :: proc(numer, denom: long) -> ldiv_t ---;
+	lldiv         :: proc(numer, denom: longlong) -> lldiv_t ---;
+
+	// 7.22.7 Multibyte/wide character conversion functions
+	mblen         :: proc(s: cstring, n: size_t) -> int ---;
+	mbtowc        :: proc(pwc: ^wchar_t, s: cstring, n: size_t) -> int ---;
+	wctomb        :: proc(s: ^char, wc: wchar_t) -> int ---;
+
+	// 7.22.8 Multibyte/wide string conversion functions
+	mbstowcs      :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---;
+	wcstombs      :: proc(s: ^char, pwcs: ^wchar_t, n: size_t) -> size_t ---;
+}

+ 39 - 0
core/c/libc/string.odin

@@ -0,0 +1,39 @@
+
+package libc
+
+// 7.24 String handling
+
+foreign import libc "system:c"
+
+foreign libc {
+	// 7.24.2 Copying functions
+	memcpy   :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---;
+	memmove  :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---;
+	strcpy   :: proc(s1: ^char, s2: cstring) -> ^char ---;
+	strncpy  :: proc(s1: ^char, s2: cstring, n: size_t) -> ^char ---;
+
+	// 7.24.3 Concatenation functions
+	strcat   :: proc(s1: ^char, s2: cstring) -> ^char ---;
+	strncat  :: proc(s1: ^char, s2: cstring, n: size_t) -> ^char ---;
+
+	// 7.24.4 Comparison functions
+	memcmp   :: proc(s1, s2: rawptr, n: size_t) -> int ---;
+	strcmp   :: proc(s1, s2: cstring) -> int ---;
+	strcoll  :: proc(s1, s2: cstring) -> int ---;
+	strncmp  :: proc(s1, s2: cstring, n: size_t) -> int ---;
+	strxfrm  :: proc(s1: ^char, s2: cstring, n: size_t) -> size_t ---;
+
+	// 7.24.5 Search functions
+	memchr   :: proc(s: rawptr, c: int, n: size_t) -> rawptr ---;
+	strchr   :: proc(s: cstring, c: int) -> ^char ---;
+	strcspn  :: proc(s1, s2: cstring) -> size_t ---;
+	strpbrk  :: proc(s1, s2: cstring) -> ^char ---;
+	strrchr  :: proc(s: ^char, c: int) -> ^char ---;
+	strcpn   :: proc(s1, s2: cstring) -> ^char ---;
+	strtok   :: proc(s1: ^char, s2: cstring) -> ^char ---;
+
+	// 7.24.6 Miscellaneous functions
+	memset   :: proc(s: rawptr, c: int, n: size_t) -> rawptr ---;
+	strerror :: proc(errnum: int) -> ^char ---;
+	strlen   :: proc(s: cstring) -> size_t ---;
+}

+ 134 - 0
core/c/libc/threads.odin

@@ -0,0 +1,134 @@
+package libc
+
+// 7.26 Threads
+
+thrd_start_t :: proc "c" (rawptr) -> int;
+tss_dtor_t   :: proc "c" (rawptr);
+
+when ODIN_OS == "windows" {
+	foreign import libc "system:c"
+
+	thrd_success        :: 0;                             // _Thrd_success
+	thrd_nomem          :: 1;                             // _Thrd_nomem
+	thrd_timedout       :: 2;                             // _Thrd_timedout
+	thrd_busy           :: 3;                             // _Thrd_busy
+	thrd_error          :: 4;                             // _Thrd_error
+
+	mtx_plain           :: 1;                             // _Mtx_plain
+	mtx_recursive       :: 0x100;                         // _Mtx_recursive
+	mtx_timed           :: 4;                             // _Mtx_timed
+
+	TSS_DTOR_ITERATIONS :: 4;                             // _TSS_DTOR_ITERATIONS_IMP
+
+	once_flag           :: distinct i8;                   // _Once_flag_imp_t
+	thrd_t              :: struct { _: rawptr, _: uint, } // _Thrd_t
+	tss_t               :: distinct int;                  // _Tss_imp_t
+	cnd_t               :: distinct rawptr;               // _Cnd_imp_t
+
+	// MSVCRT does not expose the C11 symbol names as what they are in C11
+	// because they held off implementing <threads.h> and C11 support for so
+	// long that people started implementing their own. To prevent symbol
+	// conflict with existing customers code they had to namespace them
+	// differently. Thus we need to alias the correct symbol names with Odin's
+	// link_name attribute.
+	@(default_calling_convention="c")
+	foreign libc {
+		// 7.26.2 Initialization functions
+		@(link_name="_Call_once")     call_once     :: proc(flag: ^once_flag, func: proc "c" ()) ---;
+		// 7.26.3 Condition variable functions
+		@(link_name="_Cnd_broadcast") cnd_broadcast :: proc(cond: ^cnd_t) -> int ---;
+		@(link_name="_Cnd_destroy")   cnd_destroy   :: proc(cond: ^cnd_t) ---;
+		@(link_name="_Cnd_init")      cnd_init      :: proc(cond: ^cnd_t) -> int ---;
+		@(link_name="_Cnd_signal")    cnd_signal    :: proc(cond: ^cnd_t) -> int ---;
+		@(link_name="_Cnd_timedwait") cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---;
+		@(link_name="_Cnd_wait")      cnd_wait      :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---;
+		
+		// 7.26.4 Mutex functions
+		@(link_name="_Mtx_destroy")   mtx_destroy   :: proc(mtx: ^mtx_t) ---;
+		@(link_name="_Mtx_init")      mtx_init      :: proc(mtx: ^mtx_t, type: int) -> int ---;
+		@(link_name="_Mtx_lock")      mtx_lock      :: proc(mtx: ^mtx_t) -> int ---;
+		@(link_name="_Mtx_timedlock") mtx_timedlock :: proc(mtx: ^mtx_t, ts: ^timespec) -> int ---;
+		@(link_name="_Mtx_trylock")   mtx_trylock   :: proc(mtx: ^mtx_t) -> int ---;
+		@(link_name="_Mtx_unlock")    mtx_unlock    :: proc(mtx: ^mtx_t) -> int ---;
+
+		// 7.26.5 Thread functions
+		@(link_name="_Thrd_create")   thrd_create   :: proc(thr: ^thr_t, func: thrd_start_t, arg: rawptr) -> int ---;
+		@(link_name="_Thrd_current")  thrd_current  :: proc() -> thrd_t ---;
+		@(link_name="_Thrd_detach")   thrd_detach   :: proc(thr: thr_t) -> int ---;
+		@(link_name="_Thrd_equal")    thrd_equal    :: proc(lhs, rhs: thrd_t) -> int ---;
+		@(link_name="_Thrd_exit")     thrd_exit     :: proc(res: int) -> ! ---;
+		@(link_name="_Thrd_join")     thrd_join     :: proc(thr: thrd_t, res: ^int) -> int ---;
+		@(link_name="_Thrd_sleep")    thrd_sleep    :: proc(duration, remaining: ^timespec) -> int ---;
+		@(link_name="_Thrd_yield")    thrd_yield    :: proc() ---;
+
+		// 7.26.6 Thread-specific storage functions
+		@(link_name="_Tss_create")    tss_create    :: proc(key: ^tss_t, dtor: tss_dtor_t) -> int ---;
+		@(link_name="_Tss_delete")    tss_delete    :: proc(key: tss_t) ---;
+		@(link_name="_Tss_get")       tss_get       :: proc(key: tss_t) -> rawptr ---;
+		@(link_name="_Tss_set")       tss_set       :: proc(key: tss_t, val: rawptr) -> int ---;
+	}
+}
+
+// GLIBC and MUSL compatible constants and types.
+when ODIN_OS == "linux" {
+	foreign import libc {
+		"system:c",
+		"system:pthread"
+	}
+
+	thrd_success        :: 0;
+	thrd_busy           :: 1;
+	thrd_error          :: 2;
+	thrd_nomem          :: 3;
+	thrd_timedout       :: 4;
+
+	mtx_plain           :: 0;
+	mtx_recursive       :: 1;
+	mtx_timed           :: 2;
+
+	TSS_DTOR_ITERATIONS :: 4;
+
+	once_flag           :: distinct int;
+	thrd_t              :: distinct ulong;
+	tss_t               :: distinct uint;
+	cnd_t               :: struct #raw_union { _: [12]int, _: [12 * size_of(int) / size_of(rawptr)]rawptr, };
+	mtx_t               :: struct #raw_union { _: [10 when size_of(long) == 8 else 6]int, _: [5 when size_of(long) == 8 else 6]rawptr, };
+
+	@(default_calling_convention="c")
+	foreign libc {
+		// 7.26.2 Initialization functions
+		call_once     :: proc(flag: ^once_flag, func: proc "c" ()) ---;
+
+		// 7.26.3 Condition variable functions
+		cnd_broadcast :: proc(cond: ^cnd_t) -> int ---;
+		cnd_destroy   :: proc(cond: ^cnd_t) ---;
+		cnd_init      :: proc(cond: ^cnd_t) -> int ---;
+		cnd_signal    :: proc(cond: ^cnd_t) -> int ---;
+		cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---;
+		cnd_wait      :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---;
+		
+		// 7.26.4 Mutex functions
+		mtx_destroy   :: proc(mtx: ^mtx_t) ---;
+		mtx_init      :: proc(mtx: ^mtx_t, type: int) -> int ---;
+		mtx_lock      :: proc(mtx: ^mtx_t) -> int ---;
+		mtx_timedlock :: proc(mtx: ^mtx_t, ts: ^timespec) -> int ---;
+		mtx_trylock   :: proc(mtx: ^mtx_t) -> int ---;
+		mtx_unlock    :: proc(mtx: ^mtx_t) -> int ---;
+
+		// 7.26.5 Thread functions
+		thrd_create   :: proc(thr: ^thrd_t, func: thrd_start_t, arg: rawptr) -> int ---;
+		thrd_current  :: proc() -> thrd_t ---;
+		thrd_detach   :: proc(thr: thrd_t) -> int ---;
+		thrd_equal    :: proc(lhs, rhs: thrd_t) -> int ---;
+		thrd_exit     :: proc(res: int) -> ! ---;
+		thrd_join     :: proc(thr: thrd_t, res: ^int) -> int ---;
+		thrd_sleep    :: proc(duration, remaining: ^timespec) -> int ---;
+		thrd_yield    :: proc() ---;
+
+		// 7.26.6 Thread-specific storage functions
+		tss_create    :: proc(key: ^tss_t, dtor: tss_dtor_t) -> int ---;
+		tss_delete    :: proc(key: tss_t) ---;
+		tss_get       :: proc(key: tss_t) -> rawptr ---;
+		tss_set       :: proc(key: tss_t, val: rawptr) -> int ---;
+	}
+}

+ 77 - 0
core/c/libc/time.odin

@@ -0,0 +1,77 @@
+package libc
+
+// 7.27 Date and time
+
+foreign import libc "system:c"
+
+// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
+// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
+when ODIN_OS == "windows" {
+	foreign libc {
+		// 7.27.2 Time manipulation functions
+		                               clock        :: proc() -> clock_t ---;
+		@(link_name="_difftime64")     difftime     :: proc(time1, time2: time_t) -> double ---;
+		                               mktime       :: proc(timeptr: ^tm) -> time_t ---;
+		@(link_name="_time64")         time         :: proc(timer: ^time_t) -> time_t ---;
+		@(link_name="_timespec64_get") timespec_get :: proc(ts: ^timespec, base: int) -> int ---;
+
+		// 7.27.3 Time conversion functions
+		                               asctime      :: proc(timeptr: ^tm) -> ^char ---;
+		@(link_name="_ctime64")        ctime        :: proc(timer: ^time_t) -> ^char ---;
+		@(link_name="_gmtime64")       gmtime       :: proc(timer: ^time_t) -> ^tm ---;
+		@(link_name="_localtime64")    localtime    :: proc(timer: ^time_t) -> ^tm ---;
+		                               strftime     :: proc(s: ^char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---;
+	}
+
+	CLOCKS_PER_SEC :: 1000;
+	TIME_UTC       :: 1;
+
+	clock_t        :: distinct long;
+	time_t         :: distinct i64;
+
+	timespec :: struct #align 8 {
+		tv_sec:  time_t,
+		tv_nsec: long,
+	}
+
+	tm :: struct #align 8 {
+		tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
+	}
+}
+
+when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
+	@(default_calling_convention="c")
+	foreign libc {
+		// 7.27.2 Time manipulation functions
+		clock        :: proc() -> clock_t ---;
+		difftime     :: proc(time1, time2: time_t) -> double ---;
+		mktime       :: proc(timeptr: ^tm) -> time_t ---;
+		time         :: proc(timer: ^time_t) -> time_t ---;
+		timespec_get :: proc(ts: ^timespec, base: int) -> int ---;
+
+		// 7.27.3 Time conversion functions
+		asctime      :: proc(timeptr: ^tm) -> ^char ---;
+		ctime        :: proc(timer: ^time_t) -> ^char ---;
+		gmtime       :: proc(timer: ^time_t) -> ^tm ---;
+		localtime    :: proc(timer: ^time_t) -> ^tm ---;
+		strftime     :: proc(s: ^char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---;
+	}
+
+	CLOCKS_PER_SEC :: 1000000;
+	TIME_UTC       :: 1;
+
+	time_t         :: distinct i64;
+
+	clock_t        :: long;
+
+	timespec :: struct {
+		tv_sec:  time_t,
+		tv_nsec: long,
+	}
+
+	tm :: struct {
+		tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
+		_: long,
+		_: rawptr,
+	}
+}

+ 82 - 0
core/c/libc/types.odin

@@ -0,0 +1,82 @@
+package libc
+
+import builtin "core:builtin"
+
+char           :: builtin.u8;  // assuming -funsigned-char
+short          :: builtin.i16;
+int            :: builtin.i32;
+long           :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64;
+longlong       :: builtin.i64;
+
+uchar          :: builtin.u8;
+ushort         :: builtin.u16;
+uint           :: builtin.u32;
+ulong          :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64;
+ulonglong      :: builtin.u64;
+
+bool           :: distinct builtin.b8;
+
+size_t         :: builtin.uint;
+wchar_t        :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32;
+
+float          :: builtin.f32;
+double         :: builtin.f64;
+
+// 7.20.1 Integer types
+int8_t         :: builtin.i8;
+uint8_t        :: builtin.u8;
+int16_t        :: builtin.i16;
+uint16_t       :: builtin.u16;
+int32_t        :: builtin.i32;
+uint32_t       :: builtin.u32;
+int64_t        :: builtin.i64;
+uint64_t       :: builtin.u64;
+
+// These are all the same in multiple libc's for multiple architectures.
+int_least8_t   :: builtin.i8;
+uint_least8_t  :: builtin.u8;
+int_least16_t  :: builtin.i16;
+uint_least16_t :: builtin.u16;
+int_least32_t  :: builtin.i32;
+uint_least32_t :: builtin.u32;
+int_least64_t  :: builtin.i64;
+uint_least64_t :: builtin.u64;
+
+// Same on Windows, Linux, and FreeBSD
+when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
+	int_fast8_t    :: builtin.i8;
+	uint_fast8_t   :: builtin.u8;
+	int_fast16_t   :: builtin.i32;
+	uint_fast16_t  :: builtin.u32;
+	int_fast32_t   :: builtin.i32;
+	uint_fast32_t  :: builtin.u32;
+	int_fast64_t   :: builtin.i64;
+	uint_fast64_t  :: builtin.u64;
+}
+
+intptr_t       :: builtin.int;
+uintptr_t      :: builtin.uintptr;
+ptrdiff_t      :: distinct intptr_t;
+
+intmax_t       :: builtin.i64;
+uintmax_t      :: builtin.u64;
+
+// Copy C's rules for type promotion here by forcing the type on the literals.
+INT8_MAX       :: int(0x7f);
+INT16_MAX      :: int(0x7fff);
+INT32_MAX      :: int(0x7fffffff);
+INT64_MAX      :: longlong(0x7fffffffffffffff);
+
+UINT8_MAX      :: int(0xff);
+UINT16_MAX     :: int(0xffff);
+UINT32_MAX     :: uint(0xffffffff);
+UINT64_MAX     :: ulonglong(0xffffffffffffffff);
+
+INT8_MIN       :: ~INT8_MAX;
+INT16_MIN      :: ~INT16_MAX;
+INT32_MIN      :: ~INT32_MAX;
+INT64_MIN      :: ~INT64_MAX;
+
+NULL           :: rawptr(uintptr(0));
+
+NDEBUG         :: !ODIN_DEBUG;

+ 17 - 0
core/c/libc/uchar.odin

@@ -0,0 +1,17 @@
+package libc
+
+// 7.28 Unicode utilities
+
+foreign import libc "system:c"
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.28.1 Restartable multibyte/wide character conversion functions
+	mbrtoc16 :: proc(pc16: ^char16_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---;
+	c16rtomb :: proc(s: ^char, c16: char16_t, ps: ^mbstate_t) -> size_t ---;
+	mbrtoc32 :: proc(pc32: ^char32_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---;
+	c32rtomb :: proc(s: ^char, c32: char32_t, ps: ^mbstate_t) -> size_t ---;
+}
+
+char16_t :: uint_least16_t;
+char32_t :: uint_least32_t;

+ 104 - 0
core/c/libc/wchar.odin

@@ -0,0 +1,104 @@
+package libc
+
+// 7.29 Extended multibyte and wide character utilities
+
+foreign import libc "system:c"
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.29.2 Formatted wide character input/output functions
+	fwprintf  :: proc(stream: ^FILE, format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+	fwscanf   :: proc(stream: ^FILE, format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+	swprintf  :: proc(stream: ^FILE, n: size_t, format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+	swscanf   :: proc(s, format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+	vfwprintf :: proc(stream: ^FILE, format: ^wchar_t, arg: va_list) -> int ---;
+	vfwscanf  :: proc(stream: ^FILE, format: ^wchar_t, arg: va_list) -> int ---;
+	vswprintf :: proc(s: ^wchar_t, n: size_t, format: ^wchar_t, arg: va_list) -> int ---;
+	vswscanf  :: proc(s, format: ^wchar_t, arg: va_list) -> int ---;
+	vwprintf  :: proc(format: ^wchar_t, arg: va_list) -> int ---;
+	vwscanf   :: proc(format: ^wchar_t, arg: va_list) -> int ---;
+	wprintf   :: proc(format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+	wscanf    :: proc(format: ^wchar_t, #c_vararg arg: ..any) -> int ---;
+
+	// 7.29.3 Wide character input/output functions
+	fwgetc    :: proc(stream: ^FILE) -> wint_t ---;
+	fgetws    :: proc(s: ^wchar_t, n: int, stream: ^FILE) -> wchar_t ---;
+	fputwc    :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---;
+	fputws    :: proc(s: ^wchar_t, stream: ^FILE) -> int ---;
+	fwide     :: proc(stream: ^FILE, mode: int) -> int ---;
+	getwc     :: proc(stream: ^FILE) -> wint_t ---;
+	getwchar  :: proc() -> wint_t ---;
+	putwc     :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---;
+	putwchar  :: proc(c: wchar_t) -> wint_t ---;
+	ungetwc   :: proc(c: wchar_t, stream: ^FILE) -> wint_t ---;
+
+	// 7.29.4 General wide string utilities
+	wcstod    :: proc(nptr: ^wchar_t, endptr: ^^wchar_t) -> double ---;
+	wcstof    :: proc(nptr: ^wchar_t, endptr: ^^wchar_t) -> float ---;
+	wcstol    :: proc(nptr: ^wchar_t, endptr: ^^wchar_t, base: int) -> long ---;
+	wcstoll   :: proc(nptr: ^wchar_t, endptr: ^^wchar_t, base: int) -> longlong ---;
+	wcstoul   :: proc(nptr: ^wchar_t, endptr: ^^wchar_t, base: int) -> ulong ---;
+	wcstoull  :: proc(nptr: ^wchar_t, endptr: ^^wchar_t, base: int) -> ulonglong ---;
+
+	// 7.29.4.2 Wide string copying functions
+	wcscpy    :: proc(s1, s2: ^wchar_t) -> ^wchar_t ---;
+	wcsncpy   :: proc(s1, s2: ^wchar_t, n: size_t) -> ^wchar_t ---;
+	wmemcpy   :: proc(s1, s2: ^wchar_t, n: size_t) -> ^wchar_t ---;
+	wmemmove  :: proc(s1, s2: ^wchar_t, n: size_t) -> ^wchar_t ---;
+
+	// 7.29.4.3 Wide string concatenation functions
+	wcscat    :: proc(s1, s2: ^wchar_t) -> ^wchar_t ---;
+	wcsncat   :: proc(s1, s2: ^wchar_t, n: size_t) -> ^wchar_t ---;
+
+	// 7.29.4.4 Wide string comparison functions
+	wcscmp    :: proc(s1, s2: ^wchar_t) -> int ---;
+	wcscoll   :: proc(s1, s2: ^wchar_t) -> int ---;
+	wcsncmp   :: proc(s1, s2: ^wchar_t, n: size_t) -> int ---;
+	wcsxfrm   :: proc(s1, s2: ^wchar_t, n: size_t) -> size_t ---;
+	wmemcmp   :: proc(s1, s2: ^wchar_t, n: size_t) -> int ---;
+
+	// 7.29.4.5 Wide string search functions
+	wcschr    :: proc(s: ^wchar_t, c: wchar_t) -> ^wchar_t ---;
+	wcscspn   :: proc(s1, s2: ^wchar_t) -> size_t ---;
+	wcspbrk   :: proc(s1, s2: ^wchar_t) -> ^wchar_t ---;
+	wcsrchr   :: proc(s: ^wchar_t, c: wchar_t) -> ^wchar_t ---;
+	wcsspn    :: proc(s1, s2: ^wchar_t) -> size_t ---;
+	wcsstr    :: proc(s1, s2: ^wchar_t) -> ^wchar_t ---;
+	wcstok    :: proc(s1, s2: ^wchar_t, ptr: ^^wchar_t) -> ^wchar_t ---;
+	wmemchr   :: proc(s: ^wchar_t, c: wchar_t, n: size_t) -> ^wchar_t ---;
+
+	// 7.29.4.6 Miscellaneous functions
+	wcslen    :: proc(s: ^wchar_t) -> size_t ---;
+	wmemset   :: proc(s: ^wchar_t, c: wchar_t, n: size_t) -> ^wchar_t ---;
+
+	// 7.29.5 Wide character time conversion functions
+	wcsftime  :: proc(s: ^wchar_t, maxsize: size_t, format: ^wchar_t, timeptr: ^tm) -> size_t ---;
+
+	// 7.29.6.1 Single-byte/wide character conversion functions
+	btowc     :: proc(c: int) -> wint_t ---;
+	wctob     :: proc(c: wint_t) -> int ---;
+
+	// 7.29.6.2 Conversion state functions
+	mbsinit   :: proc(ps: ^mbstate_t) -> int ---;
+
+	// 7.29.6.3 Restartable multibyte/wide character conversion functions
+	mbrlen    :: proc(s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---;
+	mbrtowc   :: proc(pwc: ^wchar_t, s: cstring, n: size_t, ps: ^mbstate_t) -> size_t ---;
+	wcrtomb   :: proc(s: ^char, wc: wchar_t, ps: ^mbstate_t) -> size_t ---;
+
+	// 7.29.6.4 Restartable multibyte/wide string conversion functions
+	mbsrtowcs :: proc(dst: ^wchar_t, src: ^cstring, len: size_t, ps: ^mbstate_t) -> size_t ---;
+	wcsrtombs :: proc(dst: ^char, src: ^^wchar_t, len: size_t, ps: ^mbstate_t) -> size_t ---;
+}
+
+// Large enough and aligned enough for any wide-spread in-use libc.
+mbstate_t :: struct #align 16 { _: [32]char, }
+
+// Odin does not have default argument promotion so the need for a separate type
+// here isn't necessary, though make it distinct just to be safe.
+wint_t    :: distinct wchar_t;
+
+// Calculate these values correctly regardless of what type wchar_t actually is.
+WINT_MIN  :: 0;
+WINT_MAX  :: 1 << (size_of(wint_t) * 8);
+WEOF      :: ~wint_t(0);

+ 44 - 0
core/c/libc/wctype.odin

@@ -0,0 +1,44 @@
+package libc
+
+// 7.30 Wide character classification and mapping utilities
+
+foreign import libc "system:c"
+
+when ODIN_OS == "windows" {
+	wctrans_t :: distinct wchar_t;
+	wctype_t  :: distinct ushort;
+}
+
+when ODIN_OS == "linux" {
+	wctrans_t :: distinct rawptr;
+	wctype_t  :: distinct ulong;
+}
+
+@(default_calling_convention="c")
+foreign libc {
+	// 7.30.2.1 Wide character classification functions
+	iswalnum  :: proc(wc: wint_t) -> int ---;
+	iswalpha  :: proc(wc: wint_t) -> int ---;
+	iswblank  :: proc(wc: wint_t) -> int ---;
+	iswcntrl  :: proc(wc: wint_t) -> int ---;
+	iswdigit  :: proc(wc: wint_t) -> int ---;
+	iswgraph  :: proc(wc: wint_t) -> int ---;
+	iswlower  :: proc(wc: wint_t) -> int ---;
+	iswprint  :: proc(wc: wint_t) -> int ---;
+	iswpunct  :: proc(wc: wint_t) -> int ---;
+	iswspace  :: proc(wc: wint_t) -> int ---;
+	iswupper  :: proc(wc: wint_t) -> int ---;
+	iswxdigit :: proc(wc: wint_t) -> int ---;
+
+	// 7.30.2.2 Extensible wide character classification functions
+	iswctype  :: proc(wc: wint_t, desc: wctype_t) -> int ---;
+	wctype    :: proc(property: cstring) -> wctype_t ---;
+
+	// 7.30.3 Wide character case mapping utilities
+	towlower  :: proc(wc: wint_t) -> wint_t ---;
+	towupper  :: proc(wc: wint_t) -> wint_t ---;
+
+	// 7.30.3.2 Extensible wide character case mapping functions
+	towctrans :: proc(wc: wint_t, desc: wctrans_t) -> wint_t ---;
+	wctrans   :: proc(property: cstring) -> wctrans_t ---;
+}