From 39801a304d6739365703bec1fcf50655cd5df0e9 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 25 Jan 2023 11:14:03 +0100 Subject: [PATCH] Improved support for freestanding. --- lib/std/core/mem.c3 | 2 +- lib/std/math/math.c3 | 46 +++++++------------- lib/std/math/math_nolibc/ceil.c3 | 45 ++++++++++++++++++++ lib/std/math/math_nolibc/exp2.c3 | 15 +++++++ lib/std/math/math_nolibc/floor.c3 | 46 +++++++++++++++----- lib/std/math/math_nolibc/math_nolibc.c3 | 9 ++++ lib/std/math/math_nolibc/pow.c3 | 15 +++++++ lib/std/math/math_nolibc/rempi.c3 | 10 ++--- lib/std/math/math_nolibc/round.c3 | 56 +++++++++++++++++++++++++ lib/std/math/math_nolibc/scalbn.c3 | 8 +++- lib/std/math/math_nolibc/trig.c3 | 18 +++----- lib/std/math/math_nolibc/trunc.c3 | 31 ++++++++++++++ resources/examples/brainfk.c3 | 1 - src/compiler/linker.c | 1 + src/version.h | 2 +- 15 files changed, 240 insertions(+), 65 deletions(-) create mode 100644 lib/std/math/math_nolibc/ceil.c3 create mode 100644 lib/std/math/math_nolibc/exp2.c3 create mode 100644 lib/std/math/math_nolibc/math_nolibc.c3 create mode 100644 lib/std/math/math_nolibc/pow.c3 create mode 100644 lib/std/math/math_nolibc/round.c3 create mode 100644 lib/std/math/math_nolibc/trunc.c3 diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index c1398a36f..363d1117e 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -10,7 +10,7 @@ macro @volatile_load(&x) @builtin macro @volatile_store(&x, y) @builtin { - return $$volatile_store(&x, y); + return $$volatile_store(&x, ($typeof(x))y); } enum AtomicOrdering : int diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index f484022b8..75f10c8f2 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -120,13 +120,11 @@ macro sign(x) return ($typeof(x))(x < 0 ? -1 : 1); } -$if (env::COMPILER_LIBC_AVAILABLE): - -extern fn double _atan(double x) @extname("atan"); -extern fn float _atanf(float x) @extname("atanf"); -extern fn double _atan2(double, double) @extname("atan2"); -extern fn float _atan2f(float, float) @extname("atan2f"); +/** + * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" + * @checked x + y + **/ macro atan2(x, y) { $if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid): @@ -136,6 +134,10 @@ macro atan2(x, y) $endif; } +/** + * @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value" + * @checked x + y + **/ macro atan(x) { $if ($typeof(x).typeid == float.typeid): @@ -145,32 +147,6 @@ macro atan(x) $endif; } -$else: - -macro atan2(x, y) -{ - $if ($typeof(x).typeid == float.typeid && $typeof(y).typeid == float.typeid): - return atan::_atan2f(x, y); - $else: - return atan::_atan2(x, y); - $endif; -} - -macro atan(x) -{ - $if ($typeof(x).typeid == float.typeid): - return atan::_atanf(x); - $else: - return atan::_atan(x); - $endif; -} - -$endif; - - - - - /** * @require values::@is_floatlike(x) `The input must be a floating point value or float vector` **/ @@ -625,3 +601,9 @@ macro is_nan(x) $assert(false, "Type cannot be used with is_nan"); $endswitch; } + + +extern fn double _atan(double x) @extname("atan"); +extern fn float _atanf(float x) @extname("atanf"); +extern fn double _atan2(double, double) @extname("atan2"); +extern fn float _atan2f(float, float) @extname("atan2f"); diff --git a/lib/std/math/math_nolibc/ceil.c3 b/lib/std/math/math_nolibc/ceil.c3 new file mode 100644 index 000000000..497fd62cc --- /dev/null +++ b/lib/std/math/math_nolibc/ceil.c3 @@ -0,0 +1,45 @@ +module std::math::nolibc; + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn double _ceil(double x) @weak @extname("ceil") +{ + ulong ui = bitcast(x, ulong); + int e = (int)((ui >> 52) & 0x7ff); + if (e >= 0x3ff + 52 || x == 0) return x; + // y = int(x) - x, where int(x) is an integer neighbor of x + double y = ui >> 63 ? (x - TOINT) + TOINT - x : (x + TOINT) - TOINT - x; + // special case because of non-nearest rounding modes + if (e <= 0x3ff - 1) + { + @force_eval_add(y, 0); + return ui >> 63 ? -0.0 : 1; + } + return y < 0 ? x + y + 1 : x + y; +} + + +fn float _ceilf(float x) @weak @extname("ceilf") +{ + uint u = bitcast(x, uint); + int e = (int)((u >> 23) & 0xff) - 0x7f; + switch + { + case e >= 23: + return x; + case e >= 0: + uint m = 0x007fffff >> e; + if (u & m == 0) return x; + @force_eval_add(x, 0x1p120f); + if (u >> 31 == 0) u += m; + u &= ~m; + case u >> 31 != 0: + @force_eval_add(x, 0x1p120f); + return -0.0f; + case u << 1 != 0: + return 1; + } + return bitcast(u, float); +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/exp2.c3 b/lib/std/math/math_nolibc/exp2.c3 new file mode 100644 index 000000000..61cfb025c --- /dev/null +++ b/lib/std/math/math_nolibc/exp2.c3 @@ -0,0 +1,15 @@ +module std::math::nolibc; + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn float exp2f_broken(float x) @extname("exp2f") @weak +{ + unreachable("'exp2f' not supported"); +} + +fn float exp2_broken(float x) @extname("exp2") @weak +{ + unreachable("'exp2' not supported"); +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/floor.c3 b/lib/std/math/math_nolibc/floor.c3 index 1b8534f41..1b49d6626 100644 --- a/lib/std/math/math_nolibc/floor.c3 +++ b/lib/std/math/math_nolibc/floor.c3 @@ -1,21 +1,45 @@ module std::math::nolibc; +$if (!env::COMPILER_LIBC_AVAILABLE): -fn double floor(double x) @weak @extname("floor") +fn double _floor(double x) @weak @extname("floor") { - const double TOINT = 1 / math::DOUBLE_EPSILON; ulong ui = bitcast(x, ulong); int e = (int)((ui >> 52) & 0x7ff); - double y; - if (e >= 0x3ff+52 || x == 0) return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - y = ui >> 63 ? (x - TOINT) + TOINT - x : (x + TOINT) - TOINT - x; - - /* special case because of non-nearest rounding modes */ - if (e <= 0x3ff-1) + if (e >= 0x3ff + 52 || x == 0) return x; + // y = int(x) - x, where int(x) is an integer neighbor of x + double y = ui >> 63 ? (x - TOINT) + TOINT - x : (x + TOINT) - TOINT - x; + // special case because of non-nearest rounding modes + if (e <= 0x3ff - 1) { - @volatile_load(y); + @force_eval_add(y, 0); return ui >> 63 ? -1 : 0; } return y > 0 ? x + y - 1 : x + y; -} \ No newline at end of file +} + + +fn float _floorf(float x) @weak @extname("floorf") +{ + uint u = bitcast(x, uint); + int e = (int)((u >> 23) & 0xff) - 0x7f; + switch + { + case e >= 23: + return x; + case e >= 0: + uint m = 0x007fffff >> e; + if (u & m == 0) return x; + @force_eval_add(x, 0x1p120f); + if (u >> 31) u += m; + u &= ~m; + case u >> 31 == 0: + @force_eval_add(x, 0x1p120f); + u = 0; + case (u << 1 != 0): + return -1; + } + return bitcast(u, float); +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/math_nolibc.c3 b/lib/std/math/math_nolibc/math_nolibc.c3 new file mode 100644 index 000000000..48e9d03e7 --- /dev/null +++ b/lib/std/math/math_nolibc/math_nolibc.c3 @@ -0,0 +1,9 @@ +module std::math::nolibc; + +const double TOINT = 1 / math::DOUBLE_EPSILON; +const float TOINTF = (float)(1 / math::FLOAT_EPSILON); + +macro @force_eval_add(&x, v) +{ + @volatile_store(x, @volatile_load(x) + v); +} \ No newline at end of file diff --git a/lib/std/math/math_nolibc/pow.c3 b/lib/std/math/math_nolibc/pow.c3 new file mode 100644 index 000000000..47658de5e --- /dev/null +++ b/lib/std/math/math_nolibc/pow.c3 @@ -0,0 +1,15 @@ +module std::math::nolibc; + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn float powf_broken(float x) @extname("powf") @weak +{ + unreachable("'powf' not supported"); +} + +fn float pow_broken(float x) @extname("pow") @weak +{ + unreachable("'pow' not supported"); +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/rempi.c3 b/lib/std/math/math_nolibc/rempi.c3 index 69a376e36..9b045c076 100644 --- a/lib/std/math/math_nolibc/rempi.c3 +++ b/lib/std/math/math_nolibc/rempi.c3 @@ -170,8 +170,8 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) z = q[j - 1] + fw; } // compute n - z = nolibc::scalbn(z, q0); /* actual value of z */ - z -= 8.0 * nolibc::floor(z * 0.125); /* trim off integer >= 8 */ + z = nolibc::_scalbn(z, q0); /* actual value of z */ + z -= 8.0 * nolibc::_floor(z * 0.125); /* trim off integer >= 8 */ n = (int)z; z -= (double)n; switch @@ -221,7 +221,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) if (ih == 2) { z = 1.0 - z; - if (carry != 0) z -= nolibc::scalbn(1.0, q0); + if (carry != 0) z -= nolibc::_scalbn(1.0, q0); } } @@ -265,7 +265,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) else { /* break z into 24-bit if necessary */ - z = nolibc::scalbn(z,-q0); + z = nolibc::_scalbn(z,-q0); if (z >= 0x1p24) { fw = (double)(int)(0x1p-24 * z); @@ -281,7 +281,7 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) } /* convert integer "bit" chunk to floating-point value */ - fw = nolibc::scalbn(1.0 , q0); + fw = nolibc::_scalbn(1.0 , q0); for (int i = jz; i >= 0; i --) { q[i] = fw * (double)iq[i]; diff --git a/lib/std/math/math_nolibc/round.c3 b/lib/std/math/math_nolibc/round.c3 new file mode 100644 index 000000000..1a5b47d26 --- /dev/null +++ b/lib/std/math/math_nolibc/round.c3 @@ -0,0 +1,56 @@ +module std::math::nolibc; + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn double _round(double x) @extname("round") @weak +{ + ulong u = bitcast(x, ulong); + int e = (int)((u >> 52) & 0x7ff); + if (e >= 0x3ff + 52) return x; + if (u >> 63) x = -x; + if (e < 0x3ff - 1) + { + /* raise inexact if x!=0 */ + @force_eval_add(x, TOINT); + return 0 * x; + } + double y = (x + TOINT) - TOINT - x; + switch + { + case y > 0.5: + y = y + x - 1; + case y <= -0.5: + y = y + x + 1; + default: + y = y + x; + } + if (u >> 63) y = -y; + return y; +} + +fn float roundf(float x) @extname("roundf") @weak +{ + uint u = bitcast(x, uint); + int e = (u >> 23) & 0xff; + if (e >= 0x7f + 23) return x; + if (u >> 31) x = -x; + if (e < 0x7f - 1) + { + @force_eval_add(x, TOINTF); + return 0 * x; + } + float y = (x + TOINTF) - TOINTF - x; + switch + { + case y > 0.5f: + y = y + x - 1; + case y <= -0.5f: + y = y + x + 1; + default: + y = y + x; + } + if (u >> 31) y = -y; + return y; +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/scalbn.c3 b/lib/std/math/math_nolibc/scalbn.c3 index 7d36dfb3a..32a310790 100644 --- a/lib/std/math/math_nolibc/scalbn.c3 +++ b/lib/std/math/math_nolibc/scalbn.c3 @@ -1,6 +1,8 @@ module std::math::nolibc; -fn double scalbn(double x, int n) @weak @extname("scalbn") +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn double _scalbn(double x, int n) @weak @extname("scalbn") { switch { @@ -24,4 +26,6 @@ fn double scalbn(double x, int n) @weak @extname("scalbn") } } return x * bitcast(((ulong)(0x3ff + n)) << 52, double); -} \ No newline at end of file +} + +$endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/trig.c3 b/lib/std/math/math_nolibc/trig.c3 index 43439f393..2c00bee64 100644 --- a/lib/std/math/math_nolibc/trig.c3 +++ b/lib/std/math/math_nolibc/trig.c3 @@ -149,6 +149,10 @@ fn float cosf_broken(float x) @extname("cosf") @weak { unreachable("'cosf' not supported"); } +fn float sincosf_broken(float x) @extname("sincosf") @weak +{ + unreachable("'sincosf' not supported"); +} fn double sin_broken(double x) @extname("sin") @weak { @@ -158,20 +162,10 @@ fn double cos_broken(double x) @extname("cos") @weak { unreachable("'cos' not supported"); } - -fn float roundf_broken(float x) @extname("roundf") @weak +fn double sincos_broken(double x) @extname("sincos") @weak { - unreachable("'roundf' not supported"); + unreachable("'sinccos' not supported"); } -fn double round_broken(double x) @extname("round") @weak -{ - unreachable("'round' not supported"); -} - -fn float powf_broken(float x) @extname("powf") @weak -{ - unreachable("'powf' not supported"); -} $endif; \ No newline at end of file diff --git a/lib/std/math/math_nolibc/trunc.c3 b/lib/std/math/math_nolibc/trunc.c3 new file mode 100644 index 000000000..eb909633d --- /dev/null +++ b/lib/std/math/math_nolibc/trunc.c3 @@ -0,0 +1,31 @@ +module std::math::nolibc; + +$if (!env::COMPILER_LIBC_AVAILABLE): + +fn double _trunc(double x) @weak @extname("trunc") +{ + ulong i = bitcast(x, ulong); + int e = (int)((i >> 52) & 0x7ff) - 0x3ff + 12; + if (e >= 52 + 12) return x; + if (e < 12) e = 1; + ulong m = ((ulong)-1) >> e; + if (i & m == 0) return x; + @force_eval_add(x, 0x1p120f); + i &= ~m; + return bitcast(i, double); +} + +fn float _truncf(float x) @weak @extname("truncf") +{ + uint i = bitcast(x, uint); + int e = (int)((i >> 23) & 0xff) - 0x7f + 9; + if (e >= 23 + 9) return x; + if (e < 9) e = 1; + uint m = ((uint)-1) >> e; + if (i & m == 0) return x; + @force_eval_add(x, 0x1p120f); + i &= ~m; + return bitcast(i, float); +} + +$endif; \ No newline at end of file diff --git a/resources/examples/brainfk.c3 b/resources/examples/brainfk.c3 index f2f6dadd3..e9ed4ec2a 100644 --- a/resources/examples/brainfk.c3 +++ b/resources/examples/brainfk.c3 @@ -1,4 +1,3 @@ -// #target: macos-x64 module brainfk; import std::io; diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 63e0f0d1d..2baecff7d 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -144,6 +144,7 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type) add_arg("kernel32.lib"); add_arg("ntdll.lib"); + add_arg("user32.lib"); add_arg("legacy_stdio_definitions.lib"); if (active_target.win.crt_linking == WIN_CRT_STATIC) diff --git a/src/version.h b/src/version.h index 36044fc90..a80960859 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.21" \ No newline at end of file +#define COMPILER_VERSION "0.4.22" \ No newline at end of file